Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Обзор интерфейсов хранилища идентификаторов

Интерфейсы хранилища идентификаторов описаны в следующих разделах:

Интерфейс IdentityStore

Интерфейс IdentityStore определяет SPI для взаимодействия с хранилищами идентификаторов, которые являются каталогами или базами данных, содержащими информацию об учётных записях пользователей. Реализация интерфейса IdentityStore может проверять учётные данные пользователей, предоставлять информацию о группах, к которым они принадлежат, или обоих. Чаще всего реализация IdentityStore будет взаимодействовать с внешним хранилищем идентификаторов — например, с сервером LDAP — для выполнения фактической проверки учётных данных и поиска групп, но IdentityStore также может управлять данными учётной записи пользователя.

Существует две встроенных реализации IdentityStore: хранилище идентификаторов LDAP и хранилище идентификаторов базы данных. Эти хранилища идентификаторов используют внешние хранилища, которые уже должны существовать. Реализации IdentityStore не предоставляют внешних хранилищ и не управляют ими. Для них настроены параметры связи с внешним хранилищем, используя следующие аннотации:

  • LdapIdentityStoreDefinition — настраивает хранилище идентификаторов с параметрами, необходимыми для связи с внешним сервером LDAP, проверки учётных данных пользователя и/или поиска групп пользователей.

  • DatabaseIdentityStoreDefinition — настраивает хранилище идентификаторов с параметрами, необходимыми для подключения к внешней базе данных, проверки учётных данных пользователя и/или поиска групп пользователей. Вы должны предоставить реализацию PasswordHash при настройке хранилища идентификаторов базы данных. Смотрите Интерфейс PasswordHash.

Приложение может предоставить собственное хранилище идентификаторов или использовать одно из встроенных хранилищ. Примеры обоих типов:

Реализация IdentityStore должна быть компонентом CDI, который находится контейнером и развёртывается во время выполнения, и предполагается, что он имеет нормальную область видимости. Объекты IdentityStore прежде всего предназначены для использования реализациями HttpAuthenticationMechanisms, но это не является обязательным требованием. Они могут также использоваться другими типами механизмов аутентификации или контейнерами.

Может присутствовать несколько реализаций IdentityStore. Если это так, они вызываются под управлением IdentityStoreHandler.

IdentityStoreHandler

Механизмы аутентификации не взаимодействуют напрямую с IdentityStore. Вместо этого они вызывают IdentityStoreHandler. Реализация интерфейса IdentityStoreHandler предоставляет единственный метод validate(Credential), который при вызове выполняет итерации по доступным объектам IdentityStore и возвращает агрегированный результат. IdentityStoreHandler также должен быть компонентом CDI, и предполагается, что он имеет нормальную область видимости. Во время выполнения механизм аутентификации инъецирует IdentityStoreHandler и вызывает его. IdentityStoreHandler, в свою очередь, просматривает доступные объекты IdentityStore и вызывает их для определения совокупного результата.

Существует встроенный IdentityStoreHandler, который реализует стандартный алгоритм, определённый JSR 375. Спецификация JSR 375 предоставляет полное описание алгоритма, но его можно приблизительно резюмировать следующим образом:

  • Перебирайте доступные объекты IdentityStore в порядке приоритета до тех пор, пока предоставленные учётные данные не будут проверены или пока не останется больше объектов IdentityStore.

  • Если учётные данные были проверены, выполните итерацию доступных объектов IdentityStore, предоставляющих группы, в порядке приоритетов, агрегируя группы, возвращаемые каждым хранилищем.

  • Вернуть подтверждённого пользователя и информацию о группе.

Приложение может также предоставить свой собственный IdentityStoreHandler, который может использовать любой желаемый алгоритм для выбора и вызова в объектах IdentityStore и возврата агрегированного (или неагрегированного) результата.

Методы интерфейса IdentityStore

Сам интерфейс IdentityStore имеет четыре метода:

  • validate(Credential) — проверяет учётные данные и возвращает результат этой проверки.

  • getCallerGroups(CredentialValidationResult) — возвращает группы, связанные с вызывающим субъектом, указанным в CredentialValidationResult, который представляет собой результат предыдущей успешной проверки.

  • validationTypes() — возвращает набор типов проверки (один или несколько из VALIDATE, PROVIDE_GROUPS), которые указывают операции, поддерживаемые этим объектом IdentityStore.

  • priority() — возвращает положительное целое число, представляющее самообъявленный приоритет данного IdentityStore. Более низкие значения представляют более высокий приоритет.

Поскольку getCallerGroups() является конфиденциальной операцией — она ​​может возвращать информацию о произвольных пользователях и не требует, чтобы вызывающий субъект предоставлял учётные данные пользователя или иным образом подтверждал свою личность — вызывающий субъект должен иметь разрешение IdentityStorePermission("getGroups"). Осуществление этой проверки зависит от реализации метода getCallerGroups(). Встроенные IdentityStore проверяет это разрешение, если SecurityManager настроен, а встроенный IdentityStoreHandler вызывает метод getCallerGroups() в контексте блока PrivilegedAction.

Интерфейс PasswordHash

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

Чтобы обеспечить максимальную гибкость и совместимость, хранилище идентификаторов базы данных не реализует какие-либо конкретные алгоритмы хэширования паролей. Вместо этого он определяет интерфейс PasswordHash и ожидает, что приложение предоставит реализацию PasswordHash, которая может проверять пароли из определённого хранилища, которое будет использовать приложение. Реализация PasswordHash должна быть доступна в виде компонента с областью видимости dependent и настраиваться путём предоставления полного имени нужного типа в виде значения hashAlgorithm для DatabaseIdentityStoreDefinition.

Алгоритм PasswordHash определяет три метода:

  • initialize(Map<String, String> parameters) — инициализирует PasswordHash с предоставленным отображением (Map) параметров. Хранилище идентификаторов базы данных вызывает этот метод при инициализации, передавая значение hashAlgorithmParameters аннотации @DatabaseIdentityStoreDefinition (после преобразования в отображение Map).

  • verify(char[] password, String hashedPassword) — проверяет предоставленный вызывающим субъектом пароль по сохранённому хэшу пароля, полученному из базы данных. Значение hashedPassword должно быть указано точно так, как оно было возвращено из базы данных.

  • generate(char[] password) — сгенерировать хэш предоставленного пароля. Возвращаемое значение должно быть отформатировано и закодировано точно так, как оно будет сохранено в базе данных. Хотя полезно генерировать хэш пароля, предоставленного вызывающим субъектом, во время verify(), этот метод предназначен в первую очередь для использования приложениями или реализациями IdentityStore, которые хотят поддерживать возможность управления паролями и сброса пароля без дублирования кода, используемого для проверки паролей.

Обратите внимание, что, хотя интерфейс ориентирован на хэширование паролей, он также может поддерживать альтернативные подходы, такие как двустороннее шифрование хранимых паролей.

Существует встроенная реализация Pbkdf2PasswordHash, которая поддерживает, как следует из названия, хэширование пароля PBKDF2. Она поддерживает несколько параметров, которые управляют генерацией хэш-значений (размер ключа, итерации и т. д. — см. Javadoc), и эти параметры кодируются в результирующее хэш-значение, поэтому хэши можно проверить, даже если в данный момент настроены параметры, отличные от действовавших при создании сохранённого хэша.

Хотя для обеспечения совместимости с устаревшим хранилище идентификаторов, хранящим хэши паролей в формате, отличном от Pbkdf2PasswordHash, необходимо создать пользовательский PasswordHash, разработчикам следует тщательно рассмотреть вопрос о том, является ли Pbkdf2PasswordHash достаточным для новых хранилищ удостоверений. Избегайте написания новой реализации PasswordHash без глубокого понимания связанных с этим криптографических и других соображений безопасности. Некоторые из соображений, касающихся хэширования паролей:

  • Требования к хэшированию паролей значительно отличаются от требований к хэшированию в других контекстах. В частности, скорость обычно является преимуществом при генерации хэшей, но при генерации хэшей паролей, чем медленнее, тем лучше — замедлять атаки методом перебора.

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

  • Новая случайная "соль" должна использоваться каждый раз, когда генерируется новое значение хэша пароля.

Интерфейс RememberMeIdentityStore

Интерфейс RememberMeIdentityStore представляет специальный тип хранилища идентификаторов. Он не имеет прямого отношения к интерфейсу IdentityStore. То есть он не реализует и не расширяет его. Однако он выполняет аналогичную, хотя и специализированную функцию.

В некоторых случаях приложение хочет «запомнить» аутентифицированную сессию пользователя на длительный период. Например, веб-сайт может помнить вас при посещении и запрашивать пароль только периодически, возможно, раз в две недели, если вы явно не выходите из системы.

RememberMe работает следующим образом:

  • При получении запроса от неаутентифицированного пользователя аутентификация осуществляется с помощью HttpAuthenticationMechanism, который предоставляется приложением (это необходимо — RememberMeIdentityStore можно использовать только в сочетании с предоставленным приложением HttpAuthenticationMechanism).

  • После аутентификации сконфигурированный RememberMeIdentityStore сохраняет информацию об аутентифицированной личности пользователя, чтобы впоследствии её восстановить, и генерирует долгоживущий токен «запомнить меня» для входа в систему, который отправляется обратно клиенту, возможно, как cookie.

  • При последующем посещении приложения клиент предоставляет токен для входа. Затем RememberMeIdentityStore проверяет токен и возвращает сохранённую идентификационную информацию пользователя, которая затем устанавливается как аутентифицированная идентификационная информация пользователя. Если токен недействителен или срок его действия истёк, он удаляется, пользователь снова проходит обычную аутентификацию и генерируется новый токен входа.

Интерфейс RememberMeIdentityStore определяет следующие методы:

  • generateLoginToken(CallerPrincipal caller, Set<String> groups) — сгенерировать маркер входа для недавно аутентифицированного пользователя и связать его с предоставленной информацией о вызывающем субъекте и группах.

  • removeLoginToken(String token) — удалить (предположительно истёкший или недействительный) маркер входа в систему и любую связанную информацию о вызывающем субъекте и группах.

  • validate(RememberMeCredential credential) — проверить предоставленные учётные данные и, если они действительны, вернуть информацию о вызывающем субъекте и группах. (RememberMeCredential по сути является просто держателем токена для входа в систему).

Реализация RememberMeIdentityStore должна быть компонентом CDI, и предполагается, что она имеет нормальную область видимости. Это настраивается путём добавления аннотации @RememberMe к HttpAuthenticationMechanism приложения, которая указывает, что используется RememberMeIdentityStore, и предоставляет соответствующие параметры конфигурации. Затем Interceptor, предоставленный контейнером, перехватывает вызовы к HttpAuthenticationMechanism, при необходимости вызывает RememberMeIdentityStore до и после вызовов к механизму аутентификации и гарантирует, что идентификатор пользователя правильно установлен для сессии. Спецификация JSR 375 предоставляет подробное описание требуемого поведения Interceptor-а.

Реализации RememberMeIdentityStore должны позаботиться о безопасном управлении токенами и идентификационной информацией пользователя. Например, токены входа в систему не должны содержать конфиденциальную информацию пользователя, такую ​​как учётные данные или конфиденциальные атрибуты, чтобы избежать раскрытия этой информации, если злоумышленник сможет получить доступ к токену — даже зашифрованный токен потенциально уязвим для злоумышленника с достаточным количеством времени/ресурсов. Точно так же токены должны быть зашифрованы/подписаны везде, где это возможно, и отправляться только по защищённым каналам (HTTPS). Идентификационная информация пользователя, управляемая RememberMeIdentityStore, должна храниться как можно безопаснее (сохранность при этом не обязательна — единственное влияние «забытой» сессии состоит в том, что пользователю снова будет предложено войти в систему).


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)