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

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

Первоначальной целью NTLM была проверка подлинности подключений к общим файловым ресурсам Windows. Но Microsoft внедрила эту концепцию в свою версию протокола HTTP, верную своей политике охвата и расширения в те дни. Это было почти прямолинейно, поскольку NTLM требует постоянного соединения клиент-сервер для обмена аутентификацией, в то время как HTTP-соединения закрываются, как только клиент получает ответ сервера. К счастью, недавно был представлен протокол HTTP/1.1, повышающий производительность за счет обработки нескольких запросов по одному соединению (сохранение активности). Microsoft использовала эту функцию, чтобы заставить работать расширение NTLM.

Инициировать аутентификацию NTLM со стороны сервера довольно просто. Все, что должен сделать сервер, это ответить на запрос клиента:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: NTLM

это заставляет клиента повторить запрос, предоставив токен NTLM Type1:

GET / HTTP/1.1
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAF4AA...

и тут начинается беда. Чтобы сервер мог участвовать в обмене аутентификацией NTLM с браузером, он должен иметь доступ к информации аутентификации, которую Windows хранит в своей базе данных паролей. Поскольку мой веб-сервер работает на низком, непривилегированном компьютере с Linux, он никак не может получить прямой доступ к такого рода информации. Но есть способ обойти проблему, также известный как подход «Человек посередине» или «Прокси»:

  1. передать токен Type1 на сервер Active Directory и получить токен Type2
  2. передать токен Type2 в браузер, который, в свою очередь, ответит токеном Type3
  3. отправить токен Type3 на сервер Active Directory, завершив обмен

Сервер Active Directory использует протокол LDAP. Это довольно удобно, так как в Perl есть хорошая поддержка LDAP через модуль Net::LDAP.

Аутентификация в LDAP работает путем отправки запроса на привязку вместе с некоторой информацией аутентификации, такой как имя пользователя и пароль, на сервер LDAP. Красиво и просто, за исключением того, что в этом случае это не очень полезно, поскольку мы хотели бы пройти аутентификацию с использованием многоэтапного обмена NTLM. К счастью, LDAP довольно гибок, когда дело доходит до аутентификации. Нужный нам метод называется GSS-SPNEGO. По сути, это оболочка для механизмов аутентификации NTLM и Kerberos.

С помощью SPNEGO мы можем обернуть токен Type1 в запрос SPNEGO и получить ответ, откуда можно извлечь токен Type2. Затем токен Type2 возвращается в браузер, который отвечает токеном Type3. Маркер Type3 снова помещается в структуру SPNEGO и используется для отправки второго запроса на привязку. Этот второй запрос теперь будет успешно завершен, если браузер предоставил подходящую информацию для аутентификации.

Результатом всей операции является то, что веб-сервер теперь имеет открытое и аутентифицированное соединение LDAP с сервером Active Directory. Это соединение LDAP можно использовать для получения дополнительной информации, такой как, например, членство пользователя в группе.

К сожалению, модуль Net::LDAP не имеет прямой поддержки аутентификации SPNEGO, но предоставляет большую часть инфраструктуры, необходимой для ее реализации. После нескольких дней экспериментов и изучения ASN.1 и DER в процессе я успешно создал прототип всей системы и увидел свой первый успешный обмен аутентификацией. С тех пор я почистил весь код и написал два модуля Perl:

Модуль Net::LDAP::SPNEGO предоставляет все основные строительные блоки для реализации NTLM-аутентификации в любых веб-фреймворках на основе Perl, поддерживающих поддержание клиентских соединений.

Модуль Mojolicious::Plugin:SPNEGO обеспечивает идеальную интеграцию с Mojolicious, делая чрезвычайно простой реализацию NTLM-аутентификации с переадресацией на сервер Active Directory:

Оба модуля поставляются с образцом приложения, готовым для тестирования в вашей собственной среде.

Обратите внимание, что Windows будет использовать SSO только для хостов, которые находятся в «Локальном Интернете», поэтому вам, возможно, придется добавить свою непритязательную машину Linux в этот список, используя Свойства обозревателя › Безопасность › Локальный Интернет › Сайты. › Дополнительно.