Аутентификация в Cuba используя AWS Cognito User Pools

Всем привет.
Возникла задача реализовать аутентификацию пользователей с помощью AWS Cognito User pools.
Этот сервис поддерживает Oauth2\OIDC протоколы для аутентификации, в нашем случае хватит даже implicit flow (пользовательский пароль без редиректов) но я не могу найти существующих плагинов которые бы позволили мне быстро добавить такой функционал. Если что-то уже есть открытое - подскажите что можно использовать “из коробки”.

Если готовых компонентов нету - вопрос по реализации этой фичи вручную.

Нужна реализация, которая бы поддерживала хранение и обновление JWT токенов в пользовательской сессии чтобы можно было их извлекать и использовать для аутентификации в AWS services (у нас ролевой доступ там уже есть).

После изучения документации я так понял что нужно реализовать несколько сервисных классов чтобы встроить их в cuba platform. Но не очень понятно - что правильней реализовать -

  1. свой LoginProvider и повысить ему приоритет в цепочке через:
    @Override
    public int getOrder() {
        return HIGHEST_PLATFORM_PRECEDENCE + 1;
    }
  1. использовать дефолтный провайдер LoginPasswordLoginProvider и реализовать свой собственный AuthenticationService, у которого этот провайдер вызовет AuthenticationService.login(Credentials), где я проверну всю “магию” с oidc discovery и получу access + id + refresh токены

Какой подход выглядит правильней (опыта разработки в java не очень много, в основном писал в .NET ) ?

Как реализовать хранение токенов в сессии и корректное их обновление когда access token протухает? Какие компоненты в Java\Cuba предпочтительней использовать для таких целей.

Нужно ли создавать отдельный сервис-bean для хранения AWS токенов или пользорвательская сессия шифруется при хранении и доступна только в контексте пользователя ?

Пока идея только реализовать в лоб - MyAWSTokenManager куда передавать токены пользователя и в случае протухания -возвращать обновленные. Выглядит overdesign, буду благодарен за рекомендации современных и правильных практик.

Добрый день!

А вы не смотрели пример с логином через соцсети? Мне кажется, там можете подсмотреть какие-то решения.

Смотрел, как и раздел доки с реализацией AD authentication, с login provider.
В обоих случаях решаемая проблема не совпадает с моей, ну и ручная реализация работы с Oauth очень расстраивает. Почему проблема другая - мне не нужен authorization code грант, как раз хочется implicit code flow, потому что cognito служит просто хранилищем пользователей и ролей, и наши пользователи будут заводить и получать аккаунты от нас (внутренняя система), поэтому танцы с редиректами и httphandler - избыточны и не нужны.
Вопросы были про:

  1. Есть ли готовые компоненты которые бы решили такую задачу - OAuth2 страндартизирован уже лет 7-8 как, возможно я просто не нашел готового решения (в других экосистемах эти батарейки included уже давно) - просто можно ссылку скинуть.
  2. Если таких “батареек” у кубы нету (это грустно, но в общем случается) - хочется понять правильную “ручную” реализацию - что корректнее перегрузить - провайдера или authservice, какие есть подводные камни. Есть ли механизмы у кубы где можно надежно и безопасно хранить токены для сессии и следить за их обновлением ?

На англоязычном форуме эта тема обсуждалась, но как-то заглохла.

Я, наверное, не очень понимаю вашу конфигурацию. Давайте попробую описать:

  1. Вы хотите использовать Generic UI и передавать пару login-password из CUBA экрана в Cognito, там проверять имя пользователи и пароль и, на основании этого, пускать пользователя и выдавать ему список ролей из cognito.
  2. После этого пользователь должен уметь заходить автоматически, пока его Access Token не протухнет?

Если вы не используете CUBA REST API add-on, то вы можете смело подключить Spring библиотеки для работы с OAuth2 (или даже родные библиотеки AWS Cognito) в качестве зависимостей в build.gradle и через них реализовать аутентификацию.

Если вас устраивает CUBA flow то, я бы начал с переопределения LoginPasswordAuthenticationProvider. Ну, или можете целиком сделать свой LoginProvider и включать его при необходимости, как написано в примере:

@ConditionalOnAppProperty(property = "cuba.web.ldap.enabled", value = "true")
public class LdapLoginProvider implements LoginProvider, Ordered {

В CUBA есть ещё способ перекрыть нужный сервис. Также обратите внимание на профили исполнения

Скорее всего, вам подойдет com.haulmont.cuba.security.global.UserSession. Но я не очень понимаю, зачем вам хранить токены, если общение с Cognito у вас ограничивается только аутентификацией, а дальше пользователи работают с CUBA. Если только для remember me функциональности.

Сессия пользователя - UserSession хранится только в контексте пользователя, так что можно в атрибуты сохранять токены.

В идеале - я бы сделал это отдельным проектом, а потом бы завернул в add-on типа “Cognito AWS login”, чтобы потом это можно было использовать в других проектах или просто выложить на marketplace для других :slight_smile:

1 симпатия

И вот ещё полезная ссылка: Собственный механизм аутентификации. Настройка времени жизни токена

Спасибо за подробный ответ, вы очень точно описали сценарий - передавать пару логин-пароль, аутентифицировать эту пару в cognito, получать токен и список ролей из когнито (если пользователь новый - создавать в cuba sec$user, если уже существующий - синхронизировать роли). В принципе после этого пользователь должен быть залогинен в систему.

Интересная идея на тему протухания токена, закинул в свои тудушки.
Исходная причина хранить токены когнито - мы из кубы зовем разные сервисы в aws - например подписываемся на поток событий из dynamodb или ходим в AppSync - обновлять данные чтобы по appsync subscriptions они на другие клиенты прилетали в realtime, но в общем - нужны валидные токены, следить за их обновлением надо самим и прозрачно для кубы, т.е. где-то хранить и при вызове (или по таймеру) если протухли - обновлять и отдавать свежие. Ну и эти токены также используются чтобы имперсонировать iam роли в AWS тоже, так что- полезно иметь к ним доступ в пользовательской сессии.

В итоге сейчас делаю пару сервисов которые будут заниматься менеджментом токенов, получаю их из амазона через SDK, это не OAuth в итоге, но работает также ( Oauth2 был бы просто универсальнее).

Завернуть отдельным проектом и выложить - сложная тема, это все же IP работодателя, не для себя делаю.

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

Отлично. Если будут ещё вопросы - пишите, попробуем решить.