2016-07-07 3 views
1

Предупреждение: Это очень длинный пост, просто потому, что я не знаю, как объяснить наши конкретные проблемы любым другим способом (извините).Аутентификация, использование и повторное использование пароля и учетных данных Kerberos в Java

Короткая версия:

Мы строим очень модульный набор Java-приложений (клиент и сервер на стороне). Некоторые клиенты должны аутентифицироваться на серверах, а серверы могут аутентифицироваться в разных типах хранилищ пользователей. Серверы также могут вызывать другие серверы от имени их аутентифицированного пользователя, то есть использовать свои учетные данные. До сих пор это работало хорошо, используя простые учетные данные пользователя и пароля, но теперь мы должны опционально поддерживать SSO через Kerberos (а затем и другие системы аутентификации). Пока что мы терпим неудачу (отчасти жалко).

Длинная версия:

Наша центральная библиотека Java для обработки принципалов называется Access User Layer (UAL). Эта библиотека используется как клиентских и серверных приложений и обеспечивает три типа funcationality:

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

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

Фактический доступ к хранилищу пользователей обрабатывается сконфигурированным бэкэнд. Мы предоставляем несколько бэкэндов (LDAP, WebDAV, пользовательскую базу данных JDBC, пользовательский XML-файл), которые можно настроить через единый файл конфигурации, обычно называемый useraccess.xml. Этот файл определяет, какие бэкэнд (или серверы) следует использовать и как он настроен, например. LDAP-сервер и данные структуры для LDAP-сервера или URL-адреса базы данных и учетных данных пользователя базы данных для бэкэнд базы данных. Все бэкенды реализуют одни и те же интерфейсы, поэтому код приложения не зависит от бэкендов, настроенных для конкретной установки.

В нашем продукте, UAL используется двумя различными типами приложений:

  1. клиентов (обе командной строки/настольные клиенты и веб-интерфейса приложений, открываемые пользователем в браузере). Эти приложения используют UAL для выполнения основных запросов (например, нашего приложения для браузера файлов при изменении ACL ресурса WebDAV) или основных изменений (у нас есть приложение для управления веб-сайтами). В зависимости от приложения они получают учетные данные, используемые для их операций UAL одним из следующих способов: a. Пользователь предоставляет учетные данные в командной строке при вызове приложения b. Приложение открывает диалог и предлагает пользователю ввести учетные данные, когда требуется доступ к серверу. c. Экран входа отображается, когда пользователь впервые обращается к веб-интерфейсу приложения

  2. Серверы. которые используют UAL: a. Аутентификация пользователя на основе учетных данных, предоставляемых с использованием используемого протокола (например, HTTP/WebDAV или SOAP/WSSE) b. Выполните авторизацию для пользователя на основе атрибутов пользователя (или групп пользователей) c. Выполнять операции UAL (запросы/модификации) от имени клиента d.Вызов других серверов от имени клиента, то есть проходя другой сервер учетных данных пользователя (например, через HTTP/WebDAV или SOAP/WSSE)

До сих пор все наши учетные данные не были пользователь парой имени/пароль, которые работали нормально до тех пор, пока мы обязательно сохраним эти учетные данные в сеансе пользователя, когда это необходимо, чтобы впоследствии использовать их для доступа к другому серверу. Мы могли бы сделать так, чтобы каждый вызов, который получил учетные данные или передал их на сервер, прошел через наш код, который мог хранить/предоставлять необходимые учетные данные.

Все стало намного сложнее с требованием поддерживать SSO через Kerberos. Мы пробовали несколько подходов и несколько раз меняли нашу базу кода, но каждый раз, когда мы считаем, что на правильном пути, мы понимаем, что есть одно пятно, которое мы не учитываем, которое не может работать так, как мы предполагали.

Что делает вещи настолько запутанными, так это то, что мы должны обрабатывать учетные данные несколькими способами. Вот некоторые из способов, которыми мы должны предоставить учетные данные на сервер:

  1. Via Apache HttpClient при доступе к HTTP/WebDAV сервер
  2. Через SOAP/WSSE при доступе к веб-службы
  3. Via JNDI при доступе сервер LDAP (в UAL)

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

  1. В качестве модуля входа в Apache Jackrabbit
  2. При получении SOAP/WSSE сообщение в одном из наших веб-сервисов JAX-WS

очень распространенный случай использования для нас является следующее:

  1. Клиент вызывает сервер A через SOAP, предоставляя учетные данные
  2. Сервер A извлекает учетные данные из сообщения SOAP и проверяет их (отвечает с ошибкой, если они являются недопустимыми (ошибка аутентификации), или пользователь не имеет права выполнять требуемую операцию (авторизация ошибка))
  3. Сервер A затем вызывает сервер WebDAV B от имени пользователя, передавая учетные данные пользователя, чтобы выполнить операцию WebDAV с разрешениями этого пользователя (и используя имя этого пользователя и другие атрибуты).
  4. Сервер B извлекает учетные данные из HTTP-сообщения и проверяет их
  5. Сервер B затем выполняет основной запрос в хранилище пользователя C, передавая учетные данные пользователя в хранилище пользователей (в зависимости от сконфигурированного бэкэнда UAL это может просто сравнить имя пользователя и пароль для те из пользователей, которые хранят XML-файл, или используют их для установления соединения LDAP и запрашивают хранилище LDAP в качестве этого пользователя)

И проблема в том, что в Интернете, по-видимому, очень мало информации, чтобы помочь с нашими конкретными проблемами. Во-первых, большинство ресурсов просто описывают, как настроить конфигурационный файл JAAS для контейнера, чтобы его веб-приложения выполняли аутентификации пользователей. Но наш код должен работать как на клиентах, так и на серверах и использовать один файл конфигурации, чтобы указать конфигурацию хранилища пользователя для аутентификации и основных запросов/модификаций.Кроме того, это должно работать с тем же кодом с учетными записями имени пользователя и пароля в разных магазинах пользователя (некоторые из них написаны на заказ) и с билетами Kerberos (и более поздних) с сервером LDAP. И, наконец, недостаточно иметь библиотеку аутентификации, которая достоверно сообщает нам, что пользователь предоставил правильные учетные данные (как и многие модули входа в JAAS), поскольку мы фактически должны хранить учетные данные пользователя для дальнейших вызовов.

Поскольку Apache Jackrabbit, являющийся базой для одного из наших основных компонентов, нуждается в настройке модуля входа JAAS, и уже есть модули входа JAAS для аутентификации LDAP и Kerberos, мы успешно модифицировали UAL для выполнения всех своих аутентификации через JAAS. Для этого у нас было два модуля для входа в систему для наших пользовательских бэкэндов, и мне пришлось реализовать свой собственный модуль входа в LDAP, поскольку JAAS по умолчанию успешно аутентифицировал пользователя на сервере LDAP, но затем удалил как учетные данные пользователя, так и контекст LDAP , поэтому мы не смогли выполнить дальнейший запрос LDAP с использованием тех же учетных данных. Все наши собственные модули входа в систему хранят учетные данные в наборе личных учетных данных аутентифицированного субъекта, что и делает модуль входа в систему по умолчанию JAAS по умолчанию. Используя результирующий объект, мы можем выполнить пользовательские запросы. Это работает со всеми нашими бэкендами и с паролями и с Kerberos.

Мы также смогли изменить наши службы SOAP для извлечения учетных данных из сообщения SOAP. В случае учетных данных пароля мы можем просто передать их JAAS, когда обратный вызов аутентификации запрашивает учетные данные. Однако, похоже, нет способа сделать то же самое с билетом Kerberos. Вместо этого наши SOAP-сервисы в настоящее время обрабатывают их самостоятельно, передавая их через необходимые вызовы API GSS для проверки билета, получения соответствующего билета для настроенного пользователем службы службы SOAP и создания объекта, содержащего учетные данные и информацию о пользователе. Используя этот объект, мы можем выполнять запросы/модификации через UAL. Однако это не только означает, что наши службы SOAP полностью обходят UAL при аутентификации билетов Kerberos, они также нуждаются в некоторых конфигурационных данных Kerberos (имя пользователя службы, область и файл keytab) в своей собственной конфигурации в дополнение к useraccess.xml который уже содержит те же данные (но не напрямую доступен для общего клиента UAL, поскольку эти параметры специфичны для бэкэнд UAL LDAP/Kerberos). Очевидно, что ситуация будет только ухудшаться, когда мы добавим поддержку других методов проверки подлинности на основе билета, и их также необходимо внедрить вручную в каждой службе SOAP в дополнение к бэкэнду UAL, который фактически обрабатывает доступ к хранилищу пользователей.

Худший из всех, мы по-прежнему не уверены, как получить все это на нашем сервере WebDAV на базе Jackrabbit. Jackrabbit нуждается в модуле входа в систему, что должно быть хорошо для обработки учетных данных имени пользователя и пароля, но (насколько нам известно) не удалось получить билеты Kerberos. Мы могли бы, вероятно, извлечь их вручную из заголовков HTTP, но это не остановит Jackrabbit от вызова модуля входа и модуля входа в систему из-за сбоя, поскольку он все равно будет запрашивать пароль, а затем не сможет пройти проверку подлинности с Kerberos без него.

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

+0

* «услуги полностью обходят * [наша пользовательская система auth] * при аутентификации билетов Kerberos ... им также нужна некоторая конфигурация Kerberos» * - ну, вот и все: Single-Sign-On, конечной системы, то есть Kerberos KDC. Слишком плохо для компонентов, которые не поддерживают Kerberos из коробки, и для компонентов, основанных на реализации Java, ср. https://steveloughran.gitbooks.io/kerberos_and_hadoop/content/sections/jdk_versions.html. Итог: Kerberos в порядке, если он скрыт под фирменной реализацией Microsoft; в противном случае это действительно * «Безумие за воротами» * –

ответ

1

Вы можете удалить все после

До сих пор все наши учетные данные не были пользователем пары имя/пароль, которые работали хорошо до тех пор, пока мы убедились, чтобы сохранить эти учетные данные в сеансе пользователя, где необходимо последующего использования для доступа к другому серверу.Мы могли бы сделать так, чтобы каждый вызов, который получил учетные данные или передал их на сервер, прошел через наш код, который мог хранить/предоставлять необходимые учетные данные.

Вы проблема ясно проста: вам нужно удостоверение делегирование Kerberos с. Основная методика довольно проста. Поскольку у вас есть несколько проблемных областей здесь, я бы рекомендовал разбить их, чтобы вы проблема решена:

  1. OS конфигурация/среды для Kerberos верительной делегации
  2. Как запросить делегирование службы токенов
  3. Как получить делегированный TGT от клиента
  4. Как повторно использовать TGT от клиента и запросить другую услугу токенов

Поскольку ваш входящий канал HTTP, вот ответ s:

  1. Если вы находитесь в среде Active Directory, попросите администратора установить «доверенный для делегирования» на компьютере учетную запись, которая примет контекст безопасности GSS.
  2. Это немного сложно, потому что это зависит от языка клиента и библиотеки. В Java это так же просто, как установка GSSContext.requestCredDeleg(true). Наклонитесь на остальных.
  3. Осмотрите код моего Tomcat SPNEGO/AD Authenticator library, я извлекаю TGT клиента и сохраняю его в реализации Principal, обслуживаемой методом HttpServletRequest#getPrincipal.
  4. Предполагая, что ваша базовая клиентская библиотека поддерживает GSS-API должным образом, есть в основном два способа сделать это: (1) использование явного использования учетных данных: передать делегированный экземпляр GSSCredential в клиентскую библиотеку, и это должно быть остальным. (2) неявно: оберните действие своего клиента в PrivilegedAction, постройте Subject с приватным GSSCredential и вызовите Subject.doAs с обоими. JAAS будет использовать неявные учетные данные из темы потока и выполнить операцию от имени вашего пользователя.

Похоже, вы еще не достигли пункта 2 или 3.

+0

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

+0

Кроме того, установка собственных учетных данных для пароля для объекта, отличного от Krb, позволяет нам делегировать учетные данные сложным способом (путем переноса паролей на протяжении всего пути) в наших промежуточных службах, если это необходимо, если Kerberos не является вариантом. –

+0

@MarianSchedenig, я рад, что вы можете решить проблему. Grüße nach Wien. –

Смежные вопросы