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», что придется корректировать ручками.


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



Настройки в тексте
Разделы 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.
  • +9
  • 7.2k
  • 6
Share post

Similar posts

Comments 6

    0
    Я сделал немного проще — перенёс всю логику по изменению паролей в домене на интранет-портал компании, т.е. пользователю запрещено групповыми политиками менять пароль где-либо.

    А зайдя на портал (SSL, of course) юзер может сменить пароль — а бэкенд уже подключится по LDAPS и сменит пароль в домене.
    Ну и в процессе, естественно, можно этот пароль еще куда-то применить (те же хэши и т.п.)
      0
      Ваш подход, работоспособный, но тянет за собой нарушение привычных процессов работы у пользователя (надо обучать работе в Веб-панели). Особенно если есть ряд сервисов с прозрачной авторизацией (NTLM и Kerberos наше все). Если вы поменяете пароль в Веб-панели, то привет от отвалившегося маркера безопасности вам обеспечен (а перевхоить в сеанс пользователя не круто).
      Подход выше рассчитан именно на максимально прозрачное изменение пароля, с сохранением и привычных методов и без прерывания ряда процессов.
      0
      Я в своих linux сервисах использую напрямую авторизацию в AD с помощью kerberos.
      Но вот за подсказку как сделать свой фильтр сложности пароля огромное спасибо! Давно ищу. Ибо windows не позволяет сделать это кроме как с помощью написания своей dll.
        0
        Я где могу, тоже так делаю, но вот есть ряд почтовых клиентов, которые CRAM-MD5 держат, а Kerberos нет. Некоторые древние принтеры к примеру или Login (читай в открытою) или тот-же CRAM.
        0
        Спасибо за статью. Очень пригодится для фильтрации «стандартно-безопасных» паролей вроде Aa123456
        Вот кстати информация о том, как сделать свою DLL для проверки\установки пароля Link
          0
          Pre секцию я запустить не смог, в плане проблема была в том, что генерится постоянный отказ в установке пароля. Глубоко я копать не стал, задача у меня была на тот момент иной, но нужен правильный код возврата, который, неожиданно, для успешной установки пароля должен быть не 0!

        Only users with full accounts can post comments. Log in, please.