quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

Make it possible to inject Keycloak admin client

Open michalvavrik opened this issue 3 years ago • 5 comments

closes: #26837

Keycloak admin client can be configured in application.properties and injected as a CDI bean. Also the client can work with Dev Services for Keycloak without any configuration at all (analogous to bob and alice) and OIDC token providers are leveraged as default authorization provider in case user want to access Keycloak Admin REST API with access token from request.

I wrote security-keycloak-admin-client.adoc that is part of this PR and explains "What?" and "Why?" has been done.

michalvavrik avatar Aug 07 '22 21:08 michalvavrik

cc @sberyozkin

michalvavrik avatar Aug 07 '22 21:08 michalvavrik


:waning_crescent_moon: This workflow status is outdated as a new workflow run has been triggered.


Failing Jobs - Building 7c44defb9d19f4072ff993413d4592eb0cb3bcae

Status Name Step Failures Logs Raw logs
Initial JDK 11 Build Verify extension dependencies :warning: Check → Logs Raw logs

quarkus-bot[bot] avatar Aug 07 '22 21:08 quarkus-bot[bot]


:waning_crescent_moon: This workflow status is outdated as a new workflow run has been triggered.


Failing Jobs - Building c647c8571c194cb50ac35804d6a6b2385aad7c01

Status Name Step Failures Logs Raw logs
:heavy_check_mark: JVM Tests - JDK 11
JVM Tests - JDK 11 Windows Build Failures Logs Raw logs
:heavy_check_mark: JVM Tests - JDK 17
:heavy_check_mark: JVM Tests - JDK 18

Full information is available in the Build summary check run.

Failures

:gear: JVM Tests - JDK 11 Windows #

- Failing: extensions/keycloak-admin-client-aggregator/keycloak-admin-client-reactive/deployment extensions/keycloak-admin-client-aggregator/keycloak-admin-client/deployment 
! Skipped: extensions/keycloak-authorization/deployment integration-tests/keycloak-authorization integration-tests/oidc 

:package: extensions/keycloak-admin-client-aggregator/keycloak-admin-client-reactive/deployment

io.quarkus.keycloak.admin.client.reactive.AutoconfigurationForKeycloakDevServicesTest.testGetRealms - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetRealm - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetRoles - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetUsers - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetClients - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

:package: extensions/keycloak-admin-client-aggregator/keycloak-admin-client/deployment

io.quarkus.keycloak.admin.client.reactive.AutoconfigurationForKeycloakDevServicesTest.testGetRealms - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetRealm - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetRoles - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetUsers - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

io.quarkus.keycloak.admin.client.reactive.UserConfigurationForKeycloakDevServicesTest.testGetClients - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.oidc.deployment.devservices.keycloak.KeycloakDevServicesProcessor#startKeycloakContainer threw an exception: java.lang.RuntimeException: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration

quarkus-bot[bot] avatar Aug 08 '22 01:08 quarkus-bot[bot]

Tests seems related, but are passing locally for me, I'll have a look what's different.

Update: that was test containers running on Windows, fixed.

michalvavrik avatar Aug 08 '22 06:08 michalvavrik

Good idea about starting doc-ing it, please add the links to it from security.adoc, and I think keycloak-authorization docs which mention the admin client. This new doc should also link back to Quarkus Security (security.doc) in its References section, sane way it is done for other security docs, thanks

sberyozkin avatar Aug 08 '22 09:08 sberyozkin

FYI - @sberyozkin I reflected both of your comments, but I'll push the changes tomorrow afternoon as I need re-test it after refactoring. Thank you for the feedback.

michalvavrik avatar Aug 15 '22 00:08 michalvavrik


:waning_crescent_moon: This workflow status is outdated as a new workflow run has been triggered.


Failing Jobs - Building b79e016138d5ab76ae5aaf91f5160d2e2aeeb826

Status Name Step Failures Logs Raw logs
:hourglass: JVM Tests - JDK 11 Build Failures Logs Raw logs
JVM Tests - JDK 11 Windows Build Failures Logs Raw logs
JVM Tests - JDK 17 Build Failures Logs Raw logs
JVM Tests - JDK 18 Build Failures Logs Raw logs
Native Tests - HTTP Build Failures Logs Raw logs

Full information is available in the Build summary check run.

Failures

:gear: JVM Tests - JDK 11 #

- Failing: integration-tests/rest-client 

:package: integration-tests/rest-client

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs_java_url line 29 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.trustall.ExternalTlsTrustAllTestCase.restClient line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.wronghost.ExternalWrongHostTestCase.restClient line 22 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

:gear: JVM Tests - JDK 11 Windows #

- Failing: integration-tests/rest-client 

:package: integration-tests/rest-client

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs_java_url line 29 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.trustall.ExternalTlsTrustAllTestCase.restClient line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.wronghost.ExternalWrongHostTestCase.restClient line 22 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

:gear: JVM Tests - JDK 17 #

- Failing: integration-tests/rest-client 

:package: integration-tests/rest-client

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs_java_url line 29 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.trustall.ExternalTlsTrustAllTestCase.restClient line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.wronghost.ExternalWrongHostTestCase.restClient line 22 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

:gear: JVM Tests - JDK 18 #

- Failing: integration-tests/rest-client 

:package: integration-tests/rest-client

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedTestCase.should_accept_self_signed_certs_java_url line 29 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.trustall.ExternalTlsTrustAllTestCase.restClient line 20 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.wronghost.ExternalWrongHostTestCase.restClient line 22 - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

:gear: Native Tests - HTTP #

- Failing: integration-tests/rest-client 

:package: integration-tests/rest-client

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedITCase.should_accept_self_signed_certs - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.selfsigned.ExternalSelfSignedITCase.should_accept_self_signed_certs_java_url - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.trustall.ExternalTlsTrustAllIT.restClient - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

io.quarkus.it.rest.client.wronghost.ExternalWrongHostIT.restClient - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

quarkus-bot[bot] avatar Aug 15 '22 20:08 quarkus-bot[bot]

I checked test failures - not related.

michalvavrik avatar Aug 15 '22 20:08 michalvavrik

@michalvavrik Hi, I'm sorry, but I'm still not understanding the need for the SPI module as well a few other things in the PR, why can't we just have a synthetic bean produced in the recorder, which will do:

KeycloakBuilder.builder()
                .serverUrl(KEYCLOAK_SERVER_URL)
                .realm("master")
                .clientId("admin-cli")
                .username("admin")
                .password("admin")
                .build();

where serverUrl, realm, clientId, username and password are configured ?

sberyozkin avatar Aug 16 '22 12:08 sberyozkin

Thank you for feedback as always. I will need confirmation that you mean your comments and I should drop it all.

  1. It makes no sense to me and plenty (plenty) of work went into this, but I respect your opinion and will do whatever you want. It's all showed in tests.
  2. I just want to be sure you really read the PR before I drop it, that's all...

Just write I am sure.

michalvavrik avatar Aug 16 '22 12:08 michalvavrik

Also, how else would you configure Keycloak admin client with Keycloak Dev Services without SPI? SPI is also used for OIDC to register default authorization provider. It takes access token from the request and uses it to access the Keycloak Admin REST API (as showed in docs I wrote, please have a look). Again, it would seems more rational for me to explain why do you believe we should just use pwd/username/client id/secret, authorization looks to me like a major case (existing SSO account is temporarily assigned with certain roles, as manage-realm). We have it for free, user don't have to configure anything as the access token is provided by OIDC. I added test to OIDC integration test module that shows it. Please have a look.

The example you showed with serverurl/pwd/username/client id validates only when client is created, which because you can't keep client open for long, is when request starts. Is that really the time you want to validate inputs?

michalvavrik avatar Aug 16 '22 12:08 michalvavrik

@michalvavrik Let me take a quick stab asap at what I meant, as it feels like we might be talking about different things :-) Of course, your effort is appreciated, I'm sorry if it will end up that some of your code may need to be changed - but it has happened to me a lot, including having to completely rewrite an original DevServices for KC module structure which I was convinced was best and I was not excited about having to rewrite, but then eventually I realized my original idea was not good :-)

sberyozkin avatar Aug 18 '22 14:08 sberyozkin

I appreciate the response. I understand my ideas were bad and I'm happy to drop them (even though I'd really appreciate your comment/response on authorization as these thoughts I had came from my previous practice were we used Keycloak, after all, you just suggest to ignore KeycloakBuilder#authorization method... I'll drop it anyway!).

As I'm OOTO and very busy, I'll move the PR to draft and rewrite it on 29.8.. Thank you for your time.

michalvavrik avatar Aug 18 '22 18:08 michalvavrik

@michalvavrik @sberyozkin maybe you both could have a talk so that you agree on a common plan?

gsmet avatar Aug 30 '22 11:08 gsmet

@michalvavrik

I understand my ideas were bad

No, I don't think I even implied it, and I do appreciate you were trying to innovate here :-). But IMHO it makes it much simpler to handle it step by step, right now, I believe it looks much closer to the original goal of #26837. We have a much simpler way to deal with initializing Keycloak admin object.

I'm not sure about the config of the grants though yet, I'll look asap.

Re some of your earlier points:

Keycloak admin client with Keycloak Dev Services without SPI

I'm not sure why we need to do it. Keycloak Dev Services work right now without Keycloak admin client. Does it have to use it ? May be but lets open an enhancement request and discuss the reason why we need to bring this dependency, I'm not sure we need to but may be I'm missing something.

Please allow me to also provide one else point of view - allowing to configure one client looks good in "quick start"/docs, but in production you will hardly ever have one almighty client with all the powers.

Well, it makes sense, in general. We have OidcClient able to support many targets. Do we need the same for Keycloak admin client, given that a single one can setup everything withing a given Keycloak instance, I'm not sure, but if we do need, than may be we should do it similarly to the multi-tenant setup of the oidc.

All of this can be useful for Quarkus users, but my point is, lets handle it step by step, with the dedicated issues

Thanks for your help so far

sberyozkin avatar Aug 30 '22 15:08 sberyozkin

@michalvavrik FYI: https://github.com/quarkusio/quarkus/blob/main/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientsConfig.java, and there is a support for injecting named clients in the deployment module. Have a look at in the next step please.

sberyozkin avatar Aug 30 '22 15:08 sberyozkin

Sounds good, I can see three issues (topics): authorization, dev services, multiple clients. Once this PR is done, I'll create an issue for Dev Services for Keycloak where it can be discussed whether it makes sense. If so, I'll provide impl. Thank you

michalvavrik avatar Aug 30 '22 18:08 michalvavrik