Использование Keycloak для определения тем в политиках в Eclispe Ditto

Мой текущий вариант использования: у меня есть интерфейсное приложение, в котором пользователь вошел в систему через Keycloak. Я хотел бы реализовать некоторые части Ditto HTTP API в этом интерфейсе (https://www.eclipse.org/ditto/http-api-doc.html).

Например, я хочу создать политики (https://www.eclipse.org/ditto/basic-policy.html) для авторизации. Я читал в документации, что можно использовать поставщика, совместимого с OpenID Connect, и форма имеет следующий вид: (https://www.eclipse.org/ditto/basic-policy.html#who-can-be-addressed).

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

{
    "policyId": "my.namespace:policy-a",
    "entries": {
      "owner": {
        "subjects": {
          "nginx:ditto": {
            "type": "nginx basic auth user"
          }
        },
        
    ...
}

У меня вопрос: что именно будет под претензией, если я хочу использовать Keycloak? Это также имя пользователя, которому я хочу предоставить права? И как мне получить это в моем интерфейсе, где я хочу указать политику для отправки его в Ditto впоследствии?


ОБНОВЛЕНИЕ 1:

Я попытался включить аутентификацию keycloak в Ditto, как предложено ниже и как указано здесь: https://www.eclipse.org/ditto/installation-operating.html#openid-connect

Поскольку я запускаю Ditto с Docker Compose, я добавил следующую строку в качестве переменной среды в ditto / deployment / docker / docker-compose.yml в строке 136: - Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=http://localhost:8090/auth/realms/twin Этот URL такой же, как в заявлении эмитента моего токена, который Я получаю от Keycloak.

Теперь, если я попытаюсь сделать, например, почтовый запрос с помощью Postman для {{basePath}} / things, я получаю следующую ошибку:

<html>

<head>
    <title>401 Authorization Required</title>
</head>

<body bgcolor="white">
    <center>
        <h1>401 Authorization Required</h1>
    </center>
    <hr>
    <center>nginx/1.13.12</center>
</body>

</html>

Я выбрал Bearer Token в качестве Auth в Postman и вставил новый токен. Базовая аутентификация с пользователем по умолчанию все еще работает.

введите описание изображения здесь

Должен ли я указывать новую тему / моего пользователя в Ditto раньше?


ОБНОВЛЕНИЕ 2:

Мне удалось отключить базовую аутентификацию в nginx, закомментировав auth_basic и auth_basic_user_file в nginx.conf!

Кажется, сейчас он пересылается Ditto, потому что теперь я получаю следующую ошибку с Postman:

{ 
   "status": 401, 
   "error": "gateway:jwt.issuer.notsupported", 
   "message": "The JWT issuer 'localhost:8090/auth/realms/twin' is not supported.", 
   "description": "Check if your JWT is correct." 
}

ОБНОВЛЕНИЕ 3:

Моя конфигурация в gateway.conf теперь выглядит так:

oauth {
        protocol = "http"
        openid-connect-issuers = {
          keycloak = "localhost:8090/auth/realms/twin"
        }
      }

Я также попытался добавить эти две строки в docker-compose.yml:

- Dditto.gateway.authentication.oauth.protocol=http
- Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=localhost:8090/auth/realms/twin

К сожалению, мне все еще не повезло, та же ошибка, что и выше: / Похоже, что у пользователя была аналогичная проблема с keycloak раньше (https://gitter.im/eclipse/ditto?at=5de3ff186a85195b9edcb1a6), но, к сожалению, он не упомянул о решении.

РЕДАКТИРОВАТЬ: Оказывается, я неправильно указал эти переменные, правильное решение - добавить их как часть command: java ... дополнительной информации здесь


ОБНОВЛЕНИЕ 4:

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

{
    "status": 503,
    "error": "gateway:publickey.provider.unavailable",
    "message": "The public key provider is not available.",
    "description": "If after retry it is still unavailable, please contact the service team."
}

Сообщение об ошибке из журнала:

gateway_1        | 2020-11-05 15:33:18,669 WARN  [] o.e.d.s.g.s.a.j.DittoPublicKeyProvider  - Got Exception from discovery endpoint <http://localhost:8090/auth/realms/twin/.well-known/openid-configuration>.
gateway_1        | akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1        | Caused by: java.net.ConnectException: Connection refused
...
gateway_1        | java.util.concurrent.CompletionException: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1        | Caused by: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1        | Caused by: akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1        | Caused by: java.net.ConnectException: Connection refused

Мой кейлоак определенно работает, я могу получить жетоны. Если я открываю http://localhost:8090/auth/realms/twin/.well-known/openid-configuration, который указан в первом сообщении об ошибке, я могу увидеть свою конфигурацию openid из конфигурации keycloak. Изменить: похоже, что мой контейнер шлюза не может добраться до моего контейнера keycloak, попытаюсь понять это.


ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ:

Проблема заключалась в недоступности контейнера докеров keycloak из контейнера докеров шлюза. Сейчас пользуюсь traefik:

  1. Контейнер Keycloak имеет следующий псевдоним: keycloak.localhost
  2. Конфигурация Oauth в шлюзе выглядит так:
oauth {
        protocol = "http"
        openid-connect-issuers = {
          keycloak = "keycloak.localhost/auth/realms/twin"
        }
      }
  1. Теперь шлюз может найти контейнер keycloak через псевдоним, и я все еще могу использовать пользовательский интерфейс администратора keycloak из моего localhoast: http://keycloak.localhost:8090/auth/admin/

Дополнительная информация: Traefic Blog


person raujonas    schedule 31.10.2020    source источник
comment
Похоже, что 401 выдается nginx. Вы все еще настраивали базовую аутентификацию в nginx? В этом случае запрос никогда не достигает того же уровня.   -  person Yannic Klem    schedule 03.11.2020
comment
ENABLE_DUMMY_AUTH = true в docker-compose.yml все еще был включен. Вы это имели в виду? Я отключил его, поэтому пользователь ditto по умолчанию больше не работает с базовой аутентификацией. Дополнительно я установил ENABLE_PRE_AUTHENTICATION = false. Но когда я переключаюсь на Bearer, сообщение об ошибке остается прежним. Я не знаю, как правильно отключить базовую аутентификацию, не могли бы вы дать мне еще один совет? Надо ли адаптировать файл nginx.conf?   -  person raujonas    schedule 03.11.2020
comment
Мне удалось отключить базовую аутентификацию в nginx, закомментировав auth_basic и auth_basic_user_file в nginx.conf! Кажется, сейчас он пересылается в Ditto, потому что я получаю: {status: 401, error: gateway: jwt.issuer.notsupported, message: The JWT Isser 'localhost: 8090 / auth / realms / twin 'не поддерживается., описание: проверьте правильность вашего JWT. }   -  person raujonas    schedule 03.11.2020
comment
Я обновил раздел конфигурации openid-connect-Issue. Похоже, что схема не должна быть частью конфигурации эмитента, но должна быть настроена на уровне oauth (для всех эмитентов). Я не рекомендую использовать здесь http.   -  person Yannic Klem    schedule 04.11.2020
comment
Еще раз большое спасибо за помощь! К сожалению, мне все еще не удалось заставить его работать, я обновил вопрос еще раз ..: / Я хотел бы использовать http только для тестирования.   -  person raujonas    schedule 04.11.2020
comment
Я обновил его снова (обновление 4), думаю, теперь я на шаг ближе :) Было бы здорово, если бы вы могли посмотреть еще раз.   -  person raujonas    schedule 05.11.2020
comment
Решил и обновил решение! Большое вам спасибо еще раз!   -  person raujonas    schedule 06.11.2020
comment
Прохладный. Спасибо, что поделились своим окончательным решением и всеми итерациями, пока вы его не получили. Это будет очень полезно для будущих разработчиков.   -  person Yannic Klem    schedule 06.11.2020
comment
Рад помочь! Но мне все еще интересно, почему я не могу заставить его работать с предварительно созданными образами докеров. Похоже, что моя переменная среды вообще не работает, поэтому он говорит, что по-прежнему не поддерживается jwt-эмитент, потому что список конфигураций пуст.   -  person raujonas    schedule 06.11.2020
comment
Похоже на ошибку в конфигурационном файле шлюза ditto. Не стесняйтесь создавать проблему в нашем репозитории GitHub. Мы скоро позаботимся об этом.   -  person Yannic Klem    schedule 07.11.2020
comment
Оказывается, я неправильно указал конфиги -D! Должен был опубликовать всю конфигурацию сервиса, отредактированное решение в ОБНОВЛЕНИИ 3!   -  person raujonas    schedule 10.11.2020


Ответы (1)


Что именно будет дополнительным требованием, если я хочу использовать Keycloak?

Keycloak предоставляет вам JWT.

JWT - это зашифрованный JSON, который содержит несколько полей, называемых утверждениями. Вы можете проверить, как выглядит ваш токен, посетив https://jwt.io и вставив туда свой токен. Одно из этих полей называется sub. Это дополнительная заявка.

Чтобы включить аутентификацию keycloak в eclipse ditto, вам необходимо добавить эмитента в конфигурацию ditto.

Пример можно найти здесь. Адрес должен совпадать с URL-адресом в заявлении эмитента вашего токена JWT. .

ditto.gateway.authentication {
    oauth {
      protocol = "http"
      openid-connect-issuers = {
        some-name = "localhost:8090/auth/realms/twin"
      }
    }
}

Это также имя пользователя, которому я хочу предоставить права?

В eclipse ditto на самом деле нет концепции имен пользователей. Аналогичная аутентификация Eclipse основана на субъектах авторизации. В приведенном вами примере базовой аутентификации субъект авторизации, который создается в ditto, равен nginx:ditto.

Для аутентификации JWT субъект авторизации генерируется как комбинация имени создателя соединения с открытым идентификатором, который вы настроили (в моем случае some-name), и значения дополнительного утверждения. Тема авторизации может выглядеть так: some-name:8d078113-3ee5-4dbf-8db1-eb1a6cf0fe81.

И как мне получить это в моем интерфейсе, где я хочу указать политику для отправки его в Ditto впоследствии?

Я не уверен, правильно ли я понял вопрос. Если вы имеете в виду, как аутентифицировать ваши HTTP-запросы внешнего интерфейса для eclipse ditto, вам необходимо предоставить JWT для eclipse ditto, добавив его в заголовок авторизации ваших HTTP-запросов в следующей форме:

authorization: Bearer yourJWT

Если вы имеете в виду, как узнать дополнительное утверждение JWT, вам необходимо проанализируйте JWT на объект JSON, а затем прочтите дополнительное утверждение из раздела полезной нагрузки.

person Yannic Klem    schedule 02.11.2020
comment
Спасибо Яннику за развернутый ответ! Что я имел в виду в последнем вопросе и что я до сих пор не понимаю: допустим, я хочу предоставить права другому субъекту (не мне) внутри политики, например субъекту авторизации, который вы упомянули выше (some-name). У меня нет доступа к JWT другого пользователя, чтобы получить его конкретную подпретензию, чтобы записать это в политику. Как бы я это сделал? Может, я совершенно ошибаюсь. - person raujonas; 02.11.2020
comment
Я имею в виду, что основной пример аутентификации ясен, я могу просто написать темы: {nginx: another-user: {}}, но как мне сделать это с другим пользователем при использовании OpenID Connect-совместимых поставщиков, таких как Keycloak? - person raujonas; 02.11.2020
comment
Или можно это как логины от других пользователей из keycloak? - person raujonas; 02.11.2020
comment
Вы можете рассматривать дополнительное утверждение как нечто эквивалентное имени пользователя. Поэтому, если у вас есть запрос на предоставление доступа к ресурсу, он или она должны предоставить вам стоимость дополнительных требований своих токенов. - person Yannic Klem; 02.11.2020
comment
Еще раз спасибо за разъяснения! Поскольку я запускаю Ditto с docker compose, я добавил - Dditto.gateway.authentication.oauth.openid-connect-Issuers.keycloak = localhost: 8090 / auth / realms / twin (из моего заявления эмитента токена) в качестве переменной среды службы шлюза в файле создания. С почтальоном и моим токеном на предъявителя я все еще получаю 401 Требуется авторизация, и работает только базовая аутентификация. Я попытался ОТПРАВИТЬ новую вещь: {{basePath}} / things. Что бы вы посоветовали мне найти свою ошибку? - person raujonas; 03.11.2020
comment
Пожалуйста, укажите эти новые сведения в своем первоначальном вопросе и добавьте текст ответа 401. - person Yannic Klem; 03.11.2020