Неудачный опыт с SAML: как мы полтора месяца разрабатывали решение, которое пришлось отключить
У компании был портал на Active Directory с входом по логину и паролю. Бизнес решил сделать единую сквозную авторизацию через SAML 2.0. Мы выбрали пакет aacotroneo/laravel-saml2, настроили обмен с Active Directory и запустились. Но выяснилось: пользователям приходится проходить две авторизации — сначала в нашем сервисе, затем на портале. Через неделю поступили жалобы от большинства сотрудников. Позже решение отключили. Рассказываем, почему так вышло и что мы вынесли из этого опыта.
Контекст: портал на Active Directory и наш сервис авторизации
Это история — продолжение нашего рассказа о сервисе сквозной авторизации. Напомним контекст.
У компании был портал, где работала часть сотрудников. Компьютеры находились под Active Directory. Вход в портал и на компьютеры осуществлялся по логину (не почте) и паролю.
В нашем приложении авторизации вход был другим:
-
email + пароль;
-
номер телефона + SMS-код;
-
комбинированная многофакторная авторизация.
Бизнес решил: нужно сделать единую сквозную авторизацию через Active Directory и SAML 2.0. Идея логичная — сотрудники должны входить в сервисы через свой рабочий аккаунт, без лишних паролей.
Наша команда впервые столкнулась с такой задачей. Ранее мы использовали SAML только в связке с Google.
Что такое SAML 2.0
SAML 2.0 — это XML-протокол для обмена данными аутентификации между Identity Provider (IdP) и Service Provider (SP) .
Как это обычно работает:
-
Пользователь пытается зайти в сервис (SP).
-
Сервис перенаправляет его на Identity Provider (в нашем случае — портал на Active Directory).
-
Пользователь вводит логин и пароль на стороне IdP.
-
IdP проверяет данные и отправляет сервису SAML-assertion — XML-документ с подтверждением личности.
-
Сервис доверяет IdP и пускает пользователя.
Ключевой принцип: аутентификация происходит на стороне IdP. Сервис не хранит пароль пользователя, он доверяет assertion от IdP.
Именно в этом и крылась проблема, которую бизнес не увидел.
Наша реализация: пакет и настройка
Мы изучили готовые пакеты, чтобы не писать всю обвязку с нуля. Выбрали aacotroneo/laravel-saml2 .
Почему этот пакет:
-
Содержит все необходимые роуты (metadata, ACS, SLS).
-
Позволяет настроить обмен через XML-конфигурации.
-
Даёт возможность подвязать SAML к нашей логике с ветвлением сценариев.
Важное ограничение: внешним клиентам SAML был не нужен. Его цель — только единый вход для внутренних сотрудников. Поэтому мы настроили ветвление: если пользователь — внутренний, его перенаправляет на портал; если внешний — авторизация идёт по обычной схеме.
Сторона разработки Active Directory доработала под нас XML-формат обмена. Мы запустились.
Как это работало: технические детали
Опишем полный сценарий входа для внутреннего сотрудника.
Шаг 1. Первичная идентификация в нашем сервисе
Пользователь заходил на страницу авторизации нашего сервиса и вводил email + пароль или номер телефона. Это был первый фактор.
Зачем это было нужно: мы должны были определить, нужно ли ему заходить через SAML. Если пользователь — внутренний сотрудник, система понимала это и перенаправляла его на портал.
Шаг 2. Редирект на портал с XML-телом
После первичной идентификации мы отправляли пользователя на портал с XML-телом объекта пользователя. Портал получал данные и показывал свою форму входа.
Шаг 3. Ввод логина и пароля портала
Пользователь вводил логин (не почту) и пароль от портала. Это была вторая авторизация.
Шаг 4. SAML-ответ и вход
Портал (IdP) проверял данные и отправлял SAML-assertion обратно в наш сервис. Мы валидировали assertion и завершали вход.
Сессия жила в течение рабочего дня сотрудника.
С технической точки зрения всё было настроено корректно. SAML работал. Но с точки зрения пользовательского опыта — это был провал.
Проблема: две авторизации вместо одной
Через неделю после запуска начали поступать жалобы. Большинство внутренних сотрудников сообщили: им не упростили работу, а усложнили.
Что происходило на практике:
Чтобы войти в любой из сервисов, сотруднику нужно было:
-
Авторизоваться в нашем сервисе авторизации (email/пароль или телефон).
-
Ввести логин и пароль портала.
Две разные авторизации. Два разных набора credentials.
Бизнес при решении о внедрении SAML предполагал, что авторизация будет в одной точке — данные вводятся единожды. Но этого не произошло.
Почему так вышло: ограничение, которое не услышали
Наша команда и архитектор донесли ограничение SAML до бизнеса ещё до начала разработки.
Суть ограничения:
SAML работает так, что аутентификация происходит на стороне Identity Provider (портала). Но чтобы дойти до портала, пользователь должен сначала как-то идентифицироваться в нашем сервисе — чтобы мы поняли, что он внутренний сотрудник и его нужно перенаправить на IdP.
Это создаёт две точки входа:
-
наш сервис (первичная идентификация);
-
портал (основная аутентификация через SAML).
Мы предупредили, что понадобится проходить две разные авторизации. Бизнес это не услышал.
Это не была техническая ошибка. Это было недопонимание между бизнесом и технической реальностью. Бизнес хотел «одну точку входа», но SAML в данной архитектуре этого не давал.
Результат: полтора месяца разработки и отключение
Мы отправились в полтора месяца разработки решения, которое затем были вынуждены отключить и более не использовать.
Что это дало:
-
Опыт работы с SAML 2.0 и пакетом
aacotroneo/laravel-saml2. -
Понимание ограничений протокола в контексте пользовательского опыта.
-
Урок о важности донесения технических ограничений до бизнеса на языке бизнеса.
Что это стоило:
-
Время команды — полтора месяца.
-
Негатив сотрудников — неделя жалоб.
-
Необходимость откатывать решение. Благо гибкая конфигурация, которую мы реализовали позволила быстро откатить решение.
Что мы вынесли из этой истории
1. SAML — это не «одна кнопка входа»
SAML решает задачу федеративной аутентификации, но не устраняет необходимость в первичной идентификации, если ваш сервис должен определить, куда направить пользователя. Если бизнес хочет «одну точку входа», нужно либо:
-
делать портал единственной точкой входа (пользователь идёт сразу на портал);
-
или принять две авторизации как данность.
2. Технические ограничения нужно доносить на языке бизнеса
Мы предупредили. Но, видимо, недостаточно наглядно. Урок: когда объясняете ограничение, покажите пользовательский сценарий, а не техническую схему. «Пользователь введёт пароль дважды» — понятнее, чем «SAML требует первичной идентификации на стороне SP».
3. «Не услышали» — это тоже ответственность команды
Если бизнес не услышал — значит, мы не смогли объяснить. Это неприятный, но важный вывод. Техническая правота не спасает от провала, если заказчик не понял последствий.
4. Неудачный опыт — тоже опыт
Мы получили редкий практический навык: настройка SAML с Active Directory, работа с aacotroneo/laravel-saml2, понимание XML-обмена. В следующий раз, когда возникнет задача с SAML, мы будем знать, как это делать — и какие грабли обходить.
Технические детали SAML, которые стоит знать
Для тех, кто столкнётся с похожей задачей:
Identity Provider (IdP) — сторона, которая аутентифицирует пользователя. В нашем случае — портал на Active Directory.
Service Provider (SP) — сторона, которая доверяет IdP. В нашем случае — наш сервис авторизации.
SAML Assertion — XML-документ, который IdP отправляет SP. Содержит подтверждение личности пользователя и атрибуты (email, роли и т.д.) .
ACS (Assertion Consumer Service) — endpoint на стороне SP, куда IdP отправляет assertion. В пакете aacotroneo/laravel-saml2 этот роут создаётся автоматически .
Metadata — XML-файл с настройками SP или IdP. Содержит URL, сертификаты и другие параметры для обмена. В пакете metadata доступна по роуту /{idpName}/metadata .
Сложности SAML, которые стоит учитывать:
-
сложная настройка (XML, метаданные, сертификаты);
-
сложная отладка (ошибки в XML-подписях не всегда очевидны);
-
ограниченная гибкость в пользовательских сценариях .
Заключение
Эта история — про то, что технически корректное решение может быть провальным с точки зрения пользователя.
SAML работал. Но сотрудники получили две авторизации вместо одной — и справедливо возмутились. Мы предупреждали, но нас не услышали. В итоге — полтора месяца разработки и отключение.
Это был важный урок для нашей команды. И, надеемся, полезный для тех, кто рассматривает SAML для своей инфраструктуры.