[Из песочницы] Microsoft ActiveDirectory — обновление паролей пользователей во внешних хранилищах

Статья в большей степени ориентирована на тех, кто администрирует или создает гибридное системное окружение, где основой является Windows домен и требуется иметь возможность авторизации пользователей на других платформах и системах с централизованной системой хранения учетных данных. В большинстве случаев проблем у вас не будет, но вот если вам понадобиться реализовать авторизацию, к примеру, с использованием CRAM-MD5 или другой схемы авторизации (которой нет в AD), да и вообще не поддерживающей LDAP (или не понимающие LDAP в понимание Microsoft), то эта статья для вас.Введение: Вообще, у Microsoft есть такой сервис: Password Change Notification Service (PCNS). Его назначение — вызвать событие перед изменением пароля пользователя и после, соответственно. С этими событиями может быть передан пароль в открытом виде (естественно по защищенным каналам), это то нам и нужно.Для работы с PCNS есть ряд платных продуктов с богатым функционалом и т.д., но мы попробуем сделать свой велосипед из бесплатных и доступных материалов, для чего возьмем: Все ниже делалось для Windows Server 2008R2. Итак, поехали! PasswdHk Для начала, нужно на всех контроллерах домена установить нашу библиотеку PasswdHk, именно она будет обрабатывать событие смены пароля пользователя (событие генерируется на контроллере с правами записи, выбранного пользователем автоматически, и после смены пароля, хэш распространяется по остальным контроллерам).Скачиваем установщик (для x64), и штатно ставим библиотеку. Затем нужно скопировать C:\Windows\System32\passwdhk.dll в C:\Windows\SysWOW64\.Вместе с DLL идет ещё и графическая утилита для настройки, файл примера конфигурации (reg файл) и теста работы (bat файл). Все настройки делаются в реестре и применяются при старте системы (при изменении нужно перезапускать систему).Недоделки в утилите!!! Учтите! Каждое жмаконье по кнопке Apply приведет к добавлению еще одной строки в параметре реестра «SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages», что придется корректировать ручками.

Приведу настройки для нашей лабораторной системы:

a80f51f8eb784816a00d185fbee0702c.png

Настройки в тексте Разделы Pre и Post Change задают действия соответственно до изменения пароля (можно реализовать свой собственный фильтр сложности пароля) и после изменения.Program: C:\Windows\system32\cmd.exe (Программа запускаемая для обработки события); Arguments: /c start C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe -File d:\control\check-user.ps1 (Аргументы командной строки, передаваемые программе выше); Password Escaping задает экранирование символов пароля, но к сожалению только его. Экранирование имени пользователя не происходит, ко всему прочему, dll явно не в курсе кодировок типа UTF-8, поэтому логин в кириллице будет выглядеть крайне печально (может у кого удастся произвести декодирование результата в нормальном виде?) Описанный выше вариант с запуском через команду start не случаен, он позволяет обойти специфическую проблему, когда программа, запускаемая для обработки пароля, будет выполнятся больше чем указанные таймауты (Wait Time). Так как я запускал все это на сильно нагруженном хосте с виртуальными машинами, в машине с крайне скромными ресурсами, запуск PowerShell оболочки и подгрузки модуля в холодную (после длительного ожидания), легко переваливал за 40 сек (в это время, пользователь индицировавший смену пароля тоже сидит и ждет), и при нескромных таймаутах в 30 сек вызов обработчика прерывался принудительно.

Итак, работа PasswdHk тут закончена, теперь разберемся с получением пароля на нашей стороне. PasswdHk передает пару логин и пароль в последних двух аргументах командной строки.Обработка в PowerShell Для нашей лабораторной работы я выбрал PowerShell (как модное явление, вы же можете сделать обработку на чем угодно). Import-Module ActiveDirectory $csv_file = «d:\passwd.csv» $domain=(Get-ADDomain -Server localhost).DNSRoot $user=$args[0] $passwd=$args[1] if (Get-ADUser -Filter {sAMAccountName -eq $user } -SearchScope 2 -Server localhost){ $csv = @() $csv_new = New-Object System.Object $csv_new | Add-Member -MemberType NoteProperty -Name «DOMAIN» -Value $domain $csv_new | Add-Member -MemberType NoteProperty -Name «USER» -Value $user $csv_new | Add-Member -MemberType NoteProperty -Name «PASSWD» -Value $passwd $csv += $csv_new if (Test-Path $csv_file){ $csv | ConvertTo-Csv -NoTypeInformation -delimiter »`t» ` | select -Skip 1 ` | Out-File -Encoding UTF8 -Append $csv_file } else{ $csv | ConvertTo-Csv -NoTypeInformation -delimiter »`t» ` | Out-File -Encoding UTF8 -Append $csv_file } }; Тут мы из переменных командной строки достаем пару логин и пароль, в $domain мы помещаем DNS имя домена, в котором произошло изменение пароля, и все это укладываем в CSV с тремя колонками (DOMAIN, USER, PASSWD), если поиск пользователя вернул не пустой результат (исключает случаи с именами не на латинице, можно ещё отфильтровать объекты соответствующие только пользователям, иначе машины регулярно обновляющие свои пароли вы тоже обнаружите в этом файле).Заключение Немного изменив этот пример, вы можете отправить эти пароли в любую используемую вами среду, я применил этот метод для генерации CRAM-MD5 хэшей для почтовой системе на Dovecot.

© Habrahabr.ru