Как настроить Keycloak и получить JWT со всеми шагами, выполняемыми через REST API?

Мне нужно настроить Keycloak, работающий в Docker, с областью, пользователем с учетными данными и клиентом, а затем получить JWT, как в этом запись в блоге. Если я использую пользовательский интерфейс, как показано, он работает, но мне нужно автоматизировать все шаги с помощью Keycloak REST API. Когда я это делаю, кажется, что все шаги работают, но получить JWT не удается.

Я запускаю Keycloak в Docker вот так

docker network create keycloak-network

docker run --name mysql -d \
  --net keycloak-network \
  -e MYSQL_DATABASE=keycloak \
  -e MYSQL_USER=keycloak \
  -e MYSQL_PASSWORD=password \
  -e MYSQL_ROOT_PASSWORD=root_password \
  mysql:8.0.22

docker run -d -it \
  -e DB_VENDOR=mysql \
  -e KEYCLOAK_USER=admin \
  -e KEYCLOAK_PASSWORD=admin \
  --name keycloak \
  --net keycloak-network \
  -p 8080:8080 \
  jboss/keycloak:11.0.3

Я получаю токен доступа из основной области

POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=admin" -d "password=admin" -d "grant_type=password" -d 'client_id=admin-cli' "http://localhost:8080/auth/realms/master/protocol/openid-connect/token"|jq -r '.access_token'

Затем я создаю свое царство (названное testrealm)

POST -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" -d @"${REALM_FILE}" "http://localhost:8080/auth/admin/realms"

Затем я создаю пользователя с учетными данными:

POST "http://localhost:8080/auth/admin/realms/testrealm/users" --header 'Content-Type: application/json' -H "Authorization: Bearer ${ACCESS_TOKEN}" -d {"enabled":true,"username":"testuser","email":"[email protected]","firstName":"test","lastName":"user","credentials":[{"type":"password","value":"abc123","temporary":false}]}

Я вижу нового пользователя в пользовательском интерфейсе и запись в учетных данных новых пользователей с паролем типа.

Я создаю клиента (с именем testclient)

POST -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" -d @"${CLIENT_FILE}" "http://localhost:8080/auth/admin/realms/testrealm/clients"

Я получаю необходимые идентификаторы для изменения нового клиента с помощью

GET -H "Accept: application/json" -H "Authorization: Bearer ${ACCESS_TOKEN}" "http://localhost:8080/auth/admin/realms/testrealm/authentication/flows"

извлечение BROWSER_ID из псевдонима browser и DIRECT_GRANT_ID из псевдонима direct grant.

Я обновляю клиент, меняя Access Type на confidential и Authentication Flow Overrides на Browser Flow и Direct Grant Flow.

PUT -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" --data @client.update.json "http://localhost:8080/auth/admin/realms/testrealm/clients/${clientId}"

где данные

{                                                                               
    "publicClient": false,        
    "clientAuthenticatorType": "client-secret",                                            
    "authenticationFlowBindingOverrides": {                                                                 
        "direct_grant":"${DIRECT_GRANT_ID}",
        "browser":"${BROWSER_ID}"
    }
} 

Я получаю секрет клиента с помощью

GET -H "Accept: application/json" -H "Authorization: Bearer ${ACCESS_TOKEN}" http://localhost:8080/auth/admin/realms/testrealm/clients/${CLIENT_ID}/client-secret

В этот момент, если я захожу в пользовательский интерфейс, он показывает тот же секрет клиента, который я возвращаю, и что клиент Access Type равен confidential, а Authentication Flow Overrides были установлены на browser и direct grant. Все выглядит правильно. Сервер Keycloak теперь должен быть настроен так же, как и через пользовательский интерфейс, как показано в посте.

Когда я использую команду curl, как показано в посте, чтобы получить JWT

curl -L -X POST http://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

выдает ошибку о том, что требуется https.

{"error":"invalid_request","error_description":"HTTPS required"}

Но https не требуется, когда конфигурация была выполнена через пользовательский интерфейс. На самом деле все запросы были отправлены через http, а не через https.

Затем с помощью https

curl -L -X POST https://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

я получаю эту ошибку

curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

Если я настрою Keycloak через пользовательский интерфейс, команда curl работает, поэтому я, должно быть, что-то пропустил при использовании файла REST API. Документы Keycloak не показывают этот вариант использования, поэтому они здесь не помогут.

Кто-нибудь знает, что я пропустил при использовании REST API?


person Dean Schulze    schedule 26.12.2020    source источник
comment
При переходе с http на https я должен был изменить порт на 8443. Этот порт должен быть разделен с докером, как показано в ответе ниже.   -  person Dean Schulze    schedule 06.01.2021


Ответы (1)


Опубликуйте порт 8443 контейнера Keycloak. Там будет https с самоподписанным сертификатом (поэтому отключите проверку tls в своих запросах):

docker run -d -it \
 -e DB_VENDOR=mysql \
 -e KEYCLOAK_USER=admin \
 -e KEYCLOAK_PASSWORD=admin \
 --name keycloak \
 --net keycloak-network \
 -p 8443:8443 \
 jboss/keycloak:11.0.3

Keycloak будет доступен https://localhost:8443. См. раздел требуется Keycloak Docker HTTPS.

person Jan Garaj    schedule 27.12.2020
comment
Хороший улов. Это по-прежнему оставляет загадкой, почему при настройке через пользовательский интерфейс я могу использовать порт 8080, но при настройке с помощью REST API я должен использовать порт 8443. - person Dean Schulze; 06.01.2021