Как Я Начал Делать Модуль Расширения Для Adfs И Застрял

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

Однако это было более пятнадцати лет назад, программы я писал, по моде того времени, в основном на Delphi (или чуть раньше - тоже на C/C++) - короче, на том, что есть сейчас, ну не вообще модно и не пользуется спросом.

И последние пятнадцать лет я зарабатывал на жизнь почти исключительно системным администрированием, в основном администрированием решений Microsoft, особенно Active Directory и MS Exchange. И единственное, что было связано с программированием в этой деятельности, — это написание скриптов, так сказать, на языке программирования под названием Powershell. Однако блестящие перспективы системного администрирования в плане заработка на хлеб с маслом и икрой как-то потускнели за последние полтора десятилетия, и я решил вспомнить старое ремесло.

Но при этом я решил постараться не отходить слишком далеко от знакомых тем, чтобы все же хоть как-то использовать накопленные знания.

В частности, знания о продуктах Microsoft, с которыми я имею дело вот уже пятнадцать лет. Потому что старый программистский багаж типа Delphi уже совсем не в моде, икры с ним много не получишь, а мне очень не хотелось лезть в модные front-end разработчики, меняя Powershell на JavaScript, а потом конкурировать с новыми отчеканенные ученые-компьютерщики: Я уже не ровесник, и «Прелести скриптового языка — например, неспособность отловить ошибки на этапе компиляции — дошли до меня в Powershell. Но здесь я обнаружил трудность.

Microsoft, как вы знаете, некоторое время назад решила стать облачной компанией.

И для этого начала загонять своих пользователей в облака, для чего явно решила убить все свои замечательные локальные продукты для бизнеса, такие как мой любимый Exchange. А это автоматически делает разработку программ, связанных с этими продуктами, лишенной каких-либо перспектив.

Однако, поразмыслив, я нашел, как мне показалось, приемлемый компромисс: написать расширение для службы федерации Active Directory (AD FS).

Потому что этот сервис, используемый в различных сценариях аутентификации и авторизации в распределенных системах, имеет гораздо больше шансов на выживание в современном мире, чем решения, предназначенные исключительно для «локального» использования.

В частности, его можно использовать для авторизации доступа к приложениям в облаке Microsoft на основе аутентификации Active Directory на земле.

Поэтому использование знаний и опыта работы с этим сервисом (которого у меня немного) может иметь хоть какую-то перспективу на будущее.

Что касается модуля расширения, то у меня уже была идея такого модуля многофакторной аутентификации, который мог бы, как мне кажется, найти применение для небольших предприятий.

Ну а об идее и ее реализации, возможно, расскажу позже.

И в этой статье я ограничусь рассказом о том, как начиналась эта реализация.

Еще в давние-давние времена, когда Microsoft только-только выпустила уже старую систему Windows Server 2012 R2, в которой ADFS приняла свой нынешний вид, я, по привычке к нововведениям из документации, обнаружил в этой документации подробное, почти пошаговое руководство с примерами, как сделать и подключить этот самый модуль расширения.

Тогда мне это было не нужно, но я запомнил этот факт. И вот, когда пришло время, я нашел этот мануал.

Не скажу, что это было легко — потому что Microsoft почему-то пару раз за это время переделывала свой сайт с документацией, из-за чего все ссылки терялись.

Но, в конце концов, моя цель была достигнута.

Итак, нужный документ найден.

И среду разработки я установил, и стенд для проверки работы модуля развернул, и началось.

Выбор языка реализации модуля был прост: поскольку сам модуль работает в среде .

NET CLR и поскольку примеры кода были на C#, я не стал умничать, а выбрал именно этот язык.

К счастью, я уже немного его знал, и за время работы с Powershell мне пришлось многое узнать о разных объектах .

NET, да и сам язык напомнил мне многое из того, что я знал ранее.

Ну а чтобы совсем упростить себе жизнь, я не поленился и поискал (по названиям используемых интерфейсов) пример реального модуля расширения.

И вот такой пример нашелся — когда-то кто-то из Microsoft зачем-то выложил на GitHub модуль для взаимодействия с каким-то сервисом смс-рассылок — он не очень новый, довольно громоздкий, с какой-то непонятной логикой, видимо завязано на логике.

API этого самого сервиса, описания которого у меня не было, короче, в качестве примера малопригодно.

Тем не менее, на всякий случай я тоже собрал репозиторий с этим модулем.

Первоначальный план был прост и совсем не амбициозен: написать и подключить минимальный модуль, который отдает ADFS необходимые HTML-фрагменты для страницы аутентификации, а затем, не мудрствуя лукаво, возвращает результат, что аутентификация успешно завершена.

То есть, если коротко, в одной callback-функции, которая для начала аутентификации модуль должен вернуть строку с элементом, содержащим текст типа: «Вы уверены, что вы не хакерЭ» и кнопку типа «Конечно нет» (и плюс скрытый ввод, необходимый самому ADFS, в котором он хранит контекст), и еще одну, которая для проверки возвращает результат, что проверка пройдена.

При этом из-за особенностей ADFS необходимо возвращать в результате не только признак аутентификации — значение null, но также добавить в коллекцию заявок, переданную в качестве параметра, заявку определенного типа (тип претензии — URI) со значением — типом метода аутентификации (это тоже URI, и он указывается при регистрации модуль).

Все это мне нужно было больше для проверки правильности установки стенда; Никаких подводных камней на этом этапе я не ожидал.

И как оказалось, это было напрасно.

Итак, вот оно.

С помощью копипаста из мануала и какой-то матери я собрал классы, реализующие необходимые интерфейсы.

Из эстетических соображений я изменил значение утверждения метода аутентификации: в примере использовался URI в форме типичного URL-адреса, но я хотел использовать схему (часть перед двоеточием).

Я написал скрипт для загрузки сборки в GAC и регистрации класса модуля в ADFS. И начал тестировать.

Первые пару итераций, в ходе которых были устранены мелкие недочёты в скрипте регистрации и HTML-фрагментах, прошли нормально.

Но затем процесс зашел в тупик.

В этот самый тупик Несмотря на все мои усилия, ADFS после возврата из функции обратного вызова, которая должна была сообщить об успешной аутентификации, упорно жаловалась в своем журнале событий с кодом ошибки 364 на сообщение «Microsoft.IdentityServer.RequestFailedException: для запроса не найден метод строгой аутентификации».

.

», и в веб-интерфейсе аутентификации соответственно сообщило, что произошла ошибка.

То есть ADFS не захотела видеть оператор с тем методом аутентификации, который я ему вернул.

Для начала я вернул значение оператора к тому, что было в мануале (мало ли, может ADFS захочет там схему из URL) — не помогло.

Стало ясно, что дело серьезное.

Если бы я был настоящим программистом, я бы, наверное, подключил к процессу ADFS отладчик, поставил бы точки останова в начале функций модуля и проходил бы по ним, отслеживая путь выполнения и значения переменных.

Но так как я не настоящий программист, я просто вставил в текстовый лог отладочную печать всего, что хотел видеть в коде — контрольных точек, через которые проходит выполнение, значений переменных, возвращаемых значений.

Но и это не помогло: то, что было записано в лог, полностью соответствовало моим ожиданиям — выполнение шло как положено, то, что должно было быть возвращено — но модуль всё равно не работал.

И тут я понял, что оно пришло – пробка.

В своей предыдущей жизни программиста я не раз сталкивался с узким местом — своим или коллег.

Но это было с программами, в которых под отладчиком можно было увидеть, что происходит - вплоть до машинных инструкций и регистров процессора, а при необходимости и в вызывающем модуле: пусть исходников от него не было, но там же был машинный код, который мог подсказать, что не так с вызывающим модулем.

И это тоже было в офисе.

Где я мог подойти к коллеге (или коллега мог подойти ко мне) и попросить о помощи.

Обычно это заканчивалось на этапе объяснения того, как это работает: в какой-то момент приходил озарение, и я (или коллега) словами, обычно переводимыми на литературный русский язык как «? врика!», нашли причину и начали ее устранять.

Если озарение не приходило, то часто помогал свежий, безоблачный взгляд коллеги (или моего): ведь зачастую трудно не поверить себе и понять причину, когда ты уже убедил себя, что это должно работать и как именно должно, но свежее, неиспорченное.

С этим убеждением взгляд легче находит истину.

Но здесь я остался один, помощи ждать было неоткуда.

Оставалось только одно последнее средство.

Последнее средство выхода из завала — сделать хоть что-то.

Прежде всего, упростите (хотя в данном случае упрощению, похоже, не место).

Затем возьмите и вставьте кусочки, которые явно работают. И тут меня спас тот самый модуль, скачанный с GitHub — с вообще непонятной логикой работы, который я даже не смог запустить самостоятельно, так как у меня не было доступа к API внешнего сервиса со стенда.

Но он явно где-то работал в какой-то момент — и поэтому мог бы принести пользу и мне.

Сначала я скопировал из него URI метода аутентификации — но это не помогло.

Затем я взял код функции, выполняющей аутентификацию, вырезал из него все, кроме установки утверждения и возврата значения, и вставил этот код вместо него в аналогичное место (разумно сохранив отладочную печать в журнале).

И, о чудо, модуль заработал.

Теперь осталось понять, в чем была ошибка, и исправить ее в своем коде.

Это оказалось несложно понять, сравнив строки отладочного вывода в журнале: вставленный код возвращал правильное (как я позже проверил в документации) значение».

http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod ", а мой (точнее, скопированный из мануала) код вернул "немного" другое, неверное значение: " https://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod На глаз эту разницу увидеть сложно, но когда значения в журнале оказались одно под другим, тут же проявилась разница в длине из-за лишней буквы.

И, конечно же, после отката всех внесенных изменений в паника и исправление ошибки, все работало как положено.

Здесь должна быть мораль.

И если бы я был топ-менеджером из Microsoft, мораль была бы проста: не надо переделывать сайт документации.

Ошибка явно возникла, когда все ссылки из протокола http на протокол https были чем-то автоматически изменены: URI имени метода аутентификации, который выглядит как URL-адрес и рассматривается как URL-адрес прямо в примере кода.

Если бы сайт не был переработан, ошибки бы не возникло.

Но я не топ-менеджер в Microsoft, а потому никак не могу повлиять на ситуацию с ее документацией.

Поэтому для себя я сделал куда более скромный вывод: не стоит на 100% доверять примерам на сайтах, даже если они из официальной документации и даже если кто-то их успешно использовал какое-то время назад. Потому что в наше время документы пишет и меняет не один человек (а иногда даже бот), и никто и ничто не гарантирует, что они не будут изменены внезапно.

P.S.: Я не стал приводить ссылки на использованные фрагменты документации и репозиторий, чтобы не нарушать ход повествования.

Если они вдруг кому-то понадобятся, пишите в комментариях, дам знать.

Теги: #программирование #велосипеды

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.