Атрибут, используемый для изменения пароля: unicodePwd
. Эта документация раскрывает некоторые условия, которые должны быть выполнены для изменения пароля. Прежде всего, соединение должно быть зашифровано.
Вызов .Invoke("SetPassword", ...)
фактически вызывает собственный метод Windows IADsUser::SetPassword
. Эта документация показывает, что он автоматически пытается использовать несколько различных способов шифрования. Исключение происходит из-за того, что ни один из этих методов не сработал.
Фактически вы можете изменить атрибут unicodePwd
напрямую, не вызывая SetPassword
, к которому я доберусь, но, тем не менее, вы должны решить проблему сначала шифрование.
Когда вы запускаете это с компьютера внутри сети, AuthenticationTypes.Sealing
будет достаточно. Как в документации указано , эффект заключается в том, что он использует Kerberos для шифрования соединения.
Но когда вы подключаетесь извне домена, Kerberos не будет работать (возможно, он будет работать с усилия - я не эксперт по Kerberos). Таким образом, единственный используемый метод шифрования - это SSL. Метод SetPassword
на самом деле пытается использовать SSL, но явно не работает.
Одна проблема, которую я сразу вижу, заключается в том, что вы используете IP-адрес для подключения к D C, и SSL не будет работать с IP-адресом, поскольку имя домена в сертификате SSL должно совпадать с именем, которое вы используете для доступа к серверу, а на сертификате SSL не будет IP-адреса. Поэтому вам придется изменить это, чтобы использовать доменное имя. Если DNS не разрешит имя, вы можете добавить его в свой файл hosts.
Изменение может исправить все. В противном случае могут быть две другие проблемы:
- Порт 636 недоступен (мешает брандмауэр).
- Сертификат SSL не является доверенным на компьютере, на котором вы его запускаете. на
LDAP через SSL (LDAPS) работает на порту 636. Вы можете проверить это соединение в PowerShell:
Test-NetConnection example.com -Port 636
Если это не удается, сначала исправьте это.
Далее проверьте сертификат. Вы можете загрузить сертификат с помощью этого сценария PowerShell:
$webRequest = [Net.WebRequest]::Create("https://example.com:636")
try { $webRequest.GetResponse() } catch {}
$cert = $webRequest.ServicePoint.Certificate
$bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
set-content -value $bytes -encoding byte -path "certificate.cer"
Измените example.com
в первой строке на свое доменное имя (оставьте https://
и :636
). Тогда у вас будет файл с именем certificate.cer
в текущем каталоге, который вы можете открыть и проверить. Он предупредит вас, если ему не доверяют. Если он не является доверенным, вам нужно будет установить сертификат root на сервере в качестве доверенного сертификата Root.
Если он уже является доверенным, убедитесь, что доменное имя «Кому выдано:» на сертификат соответствует имени, которое вы использовали для подключения. В нашей среде сертификаты SSL указываются в имени каждого контроллера домена (dc1.example.com
), а не в имени домена (example.com
). Поэтому мне нужно настроить таргетинг на конкретный контроллер домена c, чтобы LDAPS работал.
Как только вы разберетесь со всем этим, ваш код должен работать.
Если вы хотите изменить * Атрибут 1056 * напрямую вместо использования SetPassword
(который может работать или не работать немного быстрее), вам нужно будет установить исходное соединение через SSL. Например:
DirectoryEntry de = new DirectoryEntry("LDAP://dc1.example.com:636","<username>", "<password>",
AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.ServerBind);
Используйте AuthenticationTypes.ServerBind
только в том случае, если вы нацеливаетесь на конкретный c D C.
Затем вы можете обновить атрибут unicodePwd
в самом конкретном c так, как он хочет:
uEntry.Properties["unicodePwd"].Value = Encoding.Unicode.GetBytes("\"NewPassword\"");
uEntry.CommitChanges();
Обратите внимание, что новый пароль должен быть заключен в кавычки.