quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.73k stars 2.67k forks source link

DevServices for Keycloak `keycloak.url` property is not available at runtime #23437

Closed twobiers closed 2 years ago

twobiers commented 2 years ago

Describe the bug

I am experimenting with the integration of the Keycloak RealmResource in my Quarkus Application. To the best of my knowledge quarkus does not offer a implementation for that, so my solution was to define some custom properties and then create a bean for the RealmResource

@ConfigMapping(prefix = "keycloak")
public interface KeycloakConfiguration {
  String serverUrl();

  String realm();

  String clientId();

  String clientSecret();
}

public class KeycloakProvider {
  private final KeycloakConfiguration keycloakConfiguration;

  @Inject
  public KeycloakProvider(KeycloakConfiguration keycloakConfiguration) {
    this.keycloakConfiguration = keycloakConfiguration;
  }

  @ApplicationScoped
  public RealmResource keycloakRealmResource() {
    return KeycloakBuilder.builder()
        .serverUrl(keycloakConfiguration.serverUrl())
        .realm(keycloakConfiguration.realm())
        .clientId(keycloakConfiguration.clientId())
        .clientSecret(keycloakConfiguration.clientSecret())
        .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
        .build().realm(keycloakConfiguration.realm());
  }
}

Next up I want to setup the application configuration for production and development. I made the oidc configuration dependent by expansion of the previously defined keycloak configuration.

quarkus.oidc.auth-server-url=${keycloak.server-url}/realms/${keycloak.realm}
quarkus.oidc.client-id=${keycloak.client-id}
quarkus.oidc.application-type=service

keycloak.client-id=my-quarkus-service
keycloak.client-secret=${KEYCLOAK_CLIENT_SECRET}
keycloak.realm=quarkus
keycloak.server-url=${keycloak.url}
%prod.keycloak.realm=my-realm
%prod.keycloak.server-url=https://production-keycloak/auth

For the production configuration that works like a charm, but with the dev services i encounter the following error.

2022-02-04 10:56:25,498 ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (vert.x-eventloop-thread-19) Uncaught exception received by Vert.x: java.util.NoSuchElementException: SRCFG00011: Could not expand value keycloak.url in property keycloak.server-url
        at io.smallrye.config.ExpressionConfigSourceInterceptor.lambda$getValue$0(ExpressionConfigSourceInterceptor.java:63)
        at io.smallrye.common.expression.ExpressionNode.emit(ExpressionNode.java:22)
        at io.smallrye.common.expression.Expression.evaluateException(Expression.java:56)
        at io.smallrye.common.expression.Expression.evaluate(Expression.java:70)
        at io.smallrye.config.ExpressionConfigSourceInterceptor.getValue(ExpressionConfigSourceInterceptor.java:56)
        at io.smallrye.config.ExpressionConfigSourceInterceptor.lambda$getValue$0(ExpressionConfigSourceInterceptor.java:57)
        at io.smallrye.common.expression.ExpressionNode.emit(ExpressionNode.java:22)
        at io.smallrye.common.expression.CompositeNode.emit(CompositeNode.java:22)
        at io.smallrye.common.expression.Expression.evaluateException(Expression.java:56)
        at io.smallrye.common.expression.Expression.evaluate(Expression.java:70)
        at io.smallrye.config.ExpressionConfigSourceInterceptor.getValue(ExpressionConfigSourceInterceptor.java:56)
        at io.smallrye.config.ExpressionConfigSourceInterceptor.getValue(ExpressionConfigSourceInterceptor.java:36)
        at io.smallrye.config.SmallRyeConfigSourceInterceptorContext.proceed(SmallRyeConfigSourceInterceptorContext.java:20)
        at io.smallrye.config.FallbackConfigSourceInterceptor.getValue(FallbackConfigSourceInterceptor.java:24)
        at io.smallrye.config.SmallRyeConfigSourceInterceptorContext.proceed(SmallRyeConfigSourceInterceptorContext.java:20)
        at io.smallrye.config.FallbackConfigSourceInterceptor.getValue(FallbackConfigSourceInterceptor.java:24)
        at io.smallrye.config.SmallRyeConfigSourceInterceptorContext.proceed(SmallRyeConfigSourceInterceptorContext.java:20)
        at io.smallrye.config.PropertyNamesConfigSourceInterceptor.getValue(PropertyNamesConfigSourceInterceptor.java:61)
        at io.smallrye.config.SmallRyeConfigSourceInterceptorContext.proceed(SmallRyeConfigSourceInterceptorContext.java:20)
        at io.smallrye.config.SmallRyeConfig.getConfigValue(SmallRyeConfig.java:305)
        at io.smallrye.config.SmallRyeConfig.getValue(SmallRyeConfig.java:223)
        at io.smallrye.config.SmallRyeConfig.getOptionalValue(SmallRyeConfig.java:322)
        at io.quarkus.vertx.http.runtime.devmode.ReplacementDebugPage.generateHtml(ReplacementDebugPage.java:62)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup.handleDeploymentProblem(VertxHttpHotReplacementSetup.java:205)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$5.handle(VertxHttpHotReplacementSetup.java:189)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$5.handle(VertxHttpHotReplacementSetup.java:185)
        at io.vertx.core.impl.future.FutureImpl$3.onFailure(FutureImpl.java:153)
        at io.vertx.core.impl.future.FutureBase.lambda$emitFailure$1(FutureBase.java:69)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)

If I'm not mistaking something the keycloak.url configuration key should be in fact available at runtime and is listed in the configuration editor when launching the application without my configuration stuff.

keycloak.url property

Another question unrelated to the problem itself is: What exactly is the purpose of the keycloak-admin-client extension? It seems to be more like a "fixing extension" than a "feature extension" if that makes any sense.

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.7.0.Final

Build tool (ie. output of mvnw --version or gradlew --version)

------------------------------------------------------------ Gradle 7.3 ------------------------------------------------------------ Build time: 2021-11-09 20:40:36 UTC Revision: 96754b8c44399658178a768ac764d727c2addb37 Kotlin: 1.5.31 Groovy: 3.0.9 Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021 JVM: 17.0.1 (Eclipse Adoptium 17.0.1+12) OS: Windows 10 10.0 amd64

Additional information

No response

quarkus-bot[bot] commented 2 years ago

/cc @evanchooly, @pedroigor, @sberyozkin, @stuartwdouglas

sberyozkin commented 2 years ago

@tobi6112 Hi, DevServices for Keycloak only uses keycloak.url for the dev/test purposes, it is not in the quarkus namespace. Similarly to client.quarkus.oidc.server-url which is there to help the tests to find Keycloak in the docker network.

DevServices for Keycloak will set quarkus.oidc.auth-server-url, quarkus.oidc.client-id, so I think you should have those set in %prod profile only.

quarkus-oidc can't really support keycloak.url as a runtime property - as it is Keycloak independent

sberyozkin commented 2 years ago

This line, https://github.com/quarkusio/quarkus/blob/main/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java#L258, should probably be removed, however, someone may already be using it in the dev or test profle, so it should stay for now.

sberyozkin commented 2 years ago

@tobi6112 I got it, %prod is actually a default profile. So in your configuration, the properties without a %prod. prefix are in fact in the prod profile. So you should add %dev. to those dev properties which would like to depend on keycloak.url; likewise you may want to add a test profile specific properties as well.

I think we can close this issue

twobiers commented 2 years ago

@sberyozkin Thanks for your fast reply and explaination, yes from my side the issue can be closed as it doesn't seem to be a bug. However, I guess my experiments are more likely to evolve into a feature request regarding the KC AdminClient later on.

sberyozkin commented 2 years ago

@tobi6112 Np; yes, KC AdminClient extension is only there to facilitate the use of this API in Quarkus and native image in paricular