SPNEGO: последующие вызовы после успешного согласования и аутентификации
За последние несколько дней я создал демонстрационную версию с использованием GSS-API и SPNEGO. Цель состоит в том, чтобы предоставить пользователям единый вход в службы, предлагаемые нашим сервером пользовательских приложений, через веб-службы RESTful Http.
Пользователь, имеющий действующий билет Kerberos Ticket Granting Ticket (TGT), может вызвать веб-сервис с поддержкой SPNEGO, клиент и сервер проведут согласование, пользователь будет аутентифицирован (как Kerberos, так и на уровне приложения) и будет (при успешной аутентификации) иметь сервисный билет для моего сервисного директора в его кэше билетов.
Это хорошо работает при использовании CURL с флагом --negotiate в качестве тестового клиента.
При первом проходе CURL делает обычный HTTP-запрос без специальных заголовков. Этот запрос отклоняется сервером, который добавляет "WWW-Authenticate: Negotiate" в заголовки ответа, предлагая согласование. Затем CURL получает билет службы от KDC и делает второй запрос, на этот раз с Negotiate + завернутый билет службы в заголовке запроса (NegTokenInit). Затем сервер разворачивает билет, проверяет подлинность пользователя и (если проверка подлинности прошла успешно). выполняет запрошенный сервис (например, логин).
Вопрос в том, что должно происходить при последующих вызовах службы от клиента к серверу? У клиента теперь есть действующий сервисный билет Kerberos, но дополнительные звонки через CURL с использованием SPNEGO выполняют те же два прохода, как описано выше.
На мой взгляд, у меня есть несколько вариантов:
1) Каждый сервисный вызов повторяет полное двухпроходное согласование SPNEGO (как делает CURL). Хотя это, возможно, самый простой вариант, по крайней мере в теории будут некоторые издержки: и клиент, и сервер создают и разрушают контексты GSS, и запрос отправляется дважды по сети, вероятно, нормально для GET, но в меньшей степени для POST, как обсуждается в следующих вопросах:
Почему строка авторизации меняется для каждого запроса firefox?
Почему Firefox продолжает согласовывать билеты на сервис Kerberos?
Но накладные расходы * заметны в реальной жизни? Я думаю, только тестирование производительности скажет.
2) Первый вызов использует согласование SPNEGO. После успешной аутентификации последующие вызовы используют аутентификацию на уровне приложения. Это может показаться подходом, принятым в Websphere Application Server, который использует маркеры безопасности облегченной сторонней аутентификации (LTPA) для последующих вызовов.
Сначала это кажется немного странным. Успешно договорившись о том, что Kerberos можно использовать, зачем возвращаться к чему-то еще? С другой стороны, этот подход может быть действительным, если можно показать, что GSS-API / SPNEGO вызывает заметные издержки / снижение производительности.
3) Первый вызов использует согласование SPNEGO. После успешной аутентификации и доверия последующие вызовы используют GSS-API Kerberos. В этом случае я мог бы также сделать вариант 4) ниже.
4) Дамп SPNEGO, используйте "чистый" GSS-API Kerberos. Я мог бы обменять билеты Kerberos через собственные заголовки Http или куки.
Есть ли лучшая практика?
В качестве фона: клиентские и серверные приложения находятся под моим контролем, оба реализованы на Java, и я знаю, что оба "говорят" на Kerberos. Я выбрал SPNEGO как "место для старта" для проверки концепции и для проникновения в мир Kerberos и Single Sign On, но это не является жестким требованием.
Доказательство концепции работает на серверах OEL Linux с FreeIPA (потому что это то, что я имею в наших подземельях), но вероятным приложением будет Windows / Active Directory.
* или значительный по сравнению с другими факторами производительности, такими как база данных, использование XML против JSON для тел сообщений и т. д.
** Если в будущем мы захотим разрешить доступ к веб-сервисам через браузер, то SPNEGO станет для вас подходом.
2 ответа
Чтобы ответить на ваш первый вопрос, GSS-SPNEGO может включать в себя несколько поездок туда и обратно. Это не ограничивается только двумя. Вы должны реализовать обработку сеанса и после успешной аутентификации выпустить cookie сеанса, который клиент должен представлять при каждом запросе. Если этот файл cookie недействителен, сервер заставит вас пройти повторную аутентификацию. Таким образом, вы будете нести расходы только тогда, когда это действительно необходимо.
В зависимости от дизайна вашего приложения вы можете выбрать разные подходы для аутентификации. В FreeIPA мы рекомендуем использовать аутентификацию внешнего интерфейса и разрешать приложениям повторно использовать тот факт, что интерфейс действительно аутентифицировал пользователя. См. http://www.freeipa.org/page/Web_App_Authentication для подробного описания различных подходов.
Я бы рекомендовал вам прочитать ссылку, указанную выше, а также проверить материалы, сделанные моим коллегой: https://www.adelton.com/ Он является автором ряда модулей Apache (и nginx), которые помогают отделить аутентификацию от реальной сети. приложения при использовании с FreeIPA.
Перечитывая мой вопрос, я действительно задавал вопрос:
a) Являются ли издержки SPNEGO достаточно значительными, чтобы их было целесообразно использовать только для авторизации, и что "что-то еще" следует использовать для последующих вызовов службы?
или же
б) Не значительны ли издержки SPNEGO в общей схеме и могут ли они использоваться для всех вызовов службы?
Ответ: это зависит от случая; и ключом к выяснению является измерение производительности сервисных вызовов с использованием SPNEGO и без него.
Сегодня я провел 4 базовых теста, используя:
- простой веб-сервис типа "ping", без SPNEGO
- простой веб-сервис типа ping с использованием SPNEGO
- звонок в сервис входа в приложение, без SPNEGO
- вызов службы входа в приложение, используя SPNEGO
Каждый тест вызывался из ksh-скрипта с циклом 60 секунд и выполнением как можно большего количества вызовов через CURL за это время.
В первых тестовых прогонах я измерил:
Без спнего
- 15 пингов
- 11 логинов
Со спенго
- 8 пингов
- 8 логинов
Первоначально это указывало на то, что с помощью SPNEGO я мог совершать только половину вызовов. Однако, если подумать, общий объем измеренных вызовов казался низким, даже с учетом плохо определенных используемых виртуальных машин.
После некоторого поиска и настройки я перезапускаю все тесты, вызывающие CURL с флагом -4 только для IPV4. Это дало следующее:
Без спнего
- 300+ пингов
- 100+ логинов
Со СПНЕГО
- 19 пингов
- 14 логинов
Это демонстрирует существенную разницу с SPNEGO и без него!
Хотя мне нужно провести дополнительное тестирование с реальными сервисами, которые выполняют некоторую внутреннюю обработку, это говорит о том, что есть веские основания для "использования чего-то другого" для последующих вызовов сервисов после аутентификации через SPNEGO.
В своих комментариях Самсон документирует прецедент в мире Hadoop и добавляет дополнительное архитектурное соображение Принципов высокораспределенного / доступного обслуживания.