Сразу признаюсь, что я не настоящий программист. То есть когда-то я был настоящим — в смысле, мне платили деньги именно за написание программ.
Однако это было более пятнадцати лет назад, программы я писал, по моде того времени, в основном на 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.: Я не стал приводить ссылки на использованные фрагменты документации и репозиторий, чтобы не нарушать ход повествования.
Если они вдруг кому-то понадобятся, пишите в комментариях, дам знать.
Теги: #программирование #велосипеды
-
Мюллер, Иоганнес Петер
19 Oct, 24 -
Предупреждаем Вас О Заражении Письменно
19 Oct, 24 -
Php Дайджест № 188 (7 – 21 Сентября 2020 Г.)
19 Oct, 24 -
Красивый Дата-Центр От Mac Pro
19 Oct, 24 -
Как Звуки И Музыка Оживляют Видеоигры
19 Oct, 24 -
Опрос Пользователей Игрового Linux
19 Oct, 24 -
Обсуждаем Платформы... Индивидуальный Подход
19 Oct, 24