#keycloak #openid-connect
#скрытый ключ #OpenID-connect
Вопрос:
У меня есть запрос о том, как keycloak должен работать с клиентом без доступа к GUI.
В принципе, у меня есть:
- Сервер скрытого ключа, настроенный с областью, клиентами (тип доступа конфиденциальный) и пользователями
- Серверное приложение с графическим интерфейсом, которое также предоставляет API, защищенное с помощью keycloak (клиент, пользователь, blablabla)
Это уже работает, поскольку я могу войти в графический интерфейс, выполнить перенаправление и т.д..
Даже доступ к API работает хорошо, когда у меня есть доступ к графическому интерфейсу: я захожу в свой пользовательский интерфейс, следую перенаправлению и заставляю свой пользовательский интерфейс отображать токен. Пользователь (чтобы отличать пользователя от приложения) может использовать токен в любом клиенте API.
В этом контексте пользователь никогда не видит секрет клиента, что инстинктивно является правильным способом. (обратите внимание, что я очень открыт для людей, которые говорят мне, что мой инстинкт неверен!)
Чего я пока не могу сделать, так это найти способ, которым серверное приложение (без GUI) может получить действительный токен?
Для авторизации authorization_endpoint, насколько я понимаю, требуются как идентификатор клиента, так и секрет клиента), чтобы получить токен, чего я бы предпочел избежать: я не думаю, что предоставление моего клиентского секрета всем моим «клиентам» является правильным способом сделать это.
В качестве альтернативы я мог бы создать API на своем клиенте, который запрашивал бы учетные данные пользователя и запрашивал токен от его имени, но это предоставило бы учетные данные клиентов моему приложению, что противоречит всей концепции!
Я попытался установить свой тип доступа клиента как общедоступный, но когда я использую приведенный ниже вызов API, я также получаю ошибку:
POST /auth/realms/realmname/protocol/openid-connect/tokenAPI
'grant_type=client_credentials'
'client_id=client_id'
'username=username'
'password=password'
{
"error": "unauthorized_client",
"error_description": "Public client not allowed to retrieve service account"
}
Кто-нибудь знает, как это должно быть сделано?
Заранее спасибо.
Макс
Комментарии:
1. Еще раз привет, если мой ответ соответствует вашим потребностям, вы не возражаете «принять» его? (ср. meta.stackexchange.com/questions/5234 / … ). Если нет, пожалуйста, дайте мне знать, чего не хватает. Это поможет нам и будущим посетителям.
Ответ №1:
(…) Серверное приложение (без графического интерфейса пользователя) может получить действительный токен… обычно используется Client Credentials
поток.
Но в этом случае мы бы определили выделенный клиент для вашего серверного (клиентского?) приложения для аутентификации. Возвращенный токен (не привязанный к конкретному пользователю) будет использоваться для авторизации в разрешенных приложениях (т. Е. ваших классических клиентах с графическим интерфейсом или API).
Итак, в принципе, вы должны (вкратце):
- определите конкретную конфиденциальную
Client
информацию в вашем Keycloak - добавьте нужные приложения (или других клиентов) к клиенту
Scope(s)
. Те, которые вы хотите авторизовать транзитивно с этого клиента. - аутентифицируйтесь на этом клиенте с
Client Credentials
потоком (учитывая конечную точку токена, идентификатор клиента, учетные данные, область действия) - убедитесь, что вы проходите аутентификацию через
TLS
и что параметры включены вrequest body
(а не в заголовки — для повышения конфиденциальности) - дальнейшее усиление безопасности вашего клиента (ов)
Если вы больше не хотите, чтобы это конкретное серверное (клиентское?) приложение получало доступ к вашим приложениям, вы можете изменить секрет / учетные данные соответствующего клиента «аутентификации» или просто удалить его.
«Я не думаю, что предоставление моего клиентского секрета всем моим «клиентам» является правильным способом сделать это».
Вы правы, и предложенный выше метод строго избегает этого. У каждого клиента будут свои собственные учетные данные.
Редактировать
(добавляю больше деталей)
Выполнив описанное выше, вы получите следующую схему:
Flow Keycloak Server
C/S app. or Customer X <--- Client Creds ---> Auth. Client X
--- Access Token ---> Appl. Client <--> Appl. Server
C/S app. or Customer Y <--- Client Creds ---> Auth. Client Y
--- Access Token ---> Appl. Client <--> Appl. Server
Browser users <--- Standard ------> Appl. Client <--> Appl. Server
Примечание: это не подробная блок-схема. Стрелки здесь в основном показывают взаимосвязи.
Наконец, пожалуйста, обратите внимание, что терминология здесь может немного отличаться, но предлагаемый метод в основном тот же, что использует Google. Таким образом, вы также можете извлечь оттуда некоторое вдохновение:
Комментарии:
1. Большое спасибо @bsaverino, кажется, это ответ на мой вопрос. Хотелось бы, чтобы был более простой способ… Есть ли способ, которым приложение-потребитель может запросить токен (токен 1) для скрытого ключа напрямую (без упоминания клиента вообще). Затем приложение вызовет API на клиенте и предоставит token1. Затем клиент вызовет keycloak со своим id / secret token1 и получит окончательный токен доступа и вернет его отправителю запроса?
2. Насколько мне известно, все потоки OAuth2, применимые к контексту M2M (где пользователи и социальные сети не имеют смысла), требуют указания идентификатора клиента. И насколько я понимаю, что вы собираетесь делать, это выглядит очень гибридно, и я бы предпочел выбрать в этом случае классический поток кода авторизации (с пользователем / паролем, т.Е. auth0.com/docs/flows/authorization-code-flow ) и внедрите в свое приложение способ возврата токена доступа пользователя (когда обычно он должен оставаться скрытым, чтобы избежать
token leakage
…).3. Я не рекомендую этот метод, поскольку возвращенный токен может предоставлять больше областей или утверждений, чем необходимо, или может быть слишком разрешительным, недолговечным или неправильно сконфигурированным для публичного / внешнего использования. В некотором смысле это в основном соответствовало бы неявному потоку, который также устарел или больше не рекомендуется по некоторым из этих причин (и фактически еще нескольким).
Ответ №2:
У меня была такая же проблема несколько недель назад
В моем случае у меня есть внутренний API и внешнее приложение, которые могут использовать пользователи. В конце концов, я не могу предоставить доступ к client_secret интерфейсному приложению.
Итак, вот мое решение:
-
При keycloak создайте клиента (например, front_end_client) с типом предоставления
public
Этот клиент будет использоваться приложением внешнего интерфейса для аутентификации пользователей с использованием неявного потока (с PKCE будет более безопасным) -
При keycloak создайте второго клиента (в той же области, что и первый клиент) с типом grant
confidential
, этот клиент будет использоваться внутренним API
Итак, вот как это работает:
-
Внешнее приложение аутентифицирует пользователей и получает токен доступа (используя font_end_client)
-
Внешнее приложение отправляет этот токен для каждого запроса на серверную часть
-
Серверное приложение проверяет этот токен и может извлекать из него разрешения