diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 8bf0b029f97e6..1fe99f3f8b4a7 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -171,7 +171,7 @@ 5.8.0 4.9.2 1.1.4.Final - 17.0.0 + 17.0.1 1.15.0 3.21.3 2.11.0 diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 0177d4e0df024..4a8633c1467c9 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -96,7 +96,7 @@ - 17.0.0 + 17.0.1 quay.io/keycloak/keycloak:${keycloak.version} quay.io/keycloak/keycloak:${keycloak.version}-legacy diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java index 0f2d667110836..e969184e2d343 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java @@ -28,7 +28,7 @@ public class DevServicesConfig { * * Image with a Quarkus based distribution is used by default. * Image with a WildFly based distribution can be selected instead, for example: - * 'quay.io/keycloak/keycloak:17.0.0-legacy'. + * 'quay.io/keycloak/keycloak:17.0.1-legacy'. *

* Note Keycloak Quarkus and Keycloak WildFly images are initialized differently. * By default, Dev Services for Keycloak will assume it is a Keycloak Quarkus image if the image version does not end with a @@ -36,7 +36,7 @@ public class DevServicesConfig { * string. * Set 'quarkus.keycloak.devservices.keycloak-x-image' to override this check. */ - @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:17.0.0") + @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:17.0.1") public String imageName; /** diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index 5aa660ab49686..703bad81487f2 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.net.ConnectException; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.URI; @@ -21,6 +22,7 @@ import java.util.Optional; import java.util.OptionalInt; import java.util.Set; +import java.util.function.Predicate; import java.util.function.Supplier; import org.eclipse.microprofile.config.ConfigProvider; @@ -58,6 +60,7 @@ import io.quarkus.oidc.deployment.devservices.OidcDevServicesUtils; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.configuration.ConfigUtils; +import io.smallrye.mutiny.Uni; import io.vertx.core.Vertx; import io.vertx.core.http.HttpHeaders; import io.vertx.mutiny.core.buffer.Buffer; @@ -407,7 +410,8 @@ protected void configure() { if (keycloakX) { addEnv(KEYCLOAK_QUARKUS_ADMIN_PROP, KEYCLOAK_ADMIN_USER); addEnv(KEYCLOAK_QUARKUS_ADMIN_PASSWORD_PROP, KEYCLOAK_ADMIN_PASSWORD); - withCommand(KEYCLOAK_QUARKUS_START_CMD); + withCommand(KEYCLOAK_QUARKUS_START_CMD + + (useSharedNetwork ? " --hostname-port=" + fixedExposedPort.getAsInt() : "")); } else { addEnv(KEYCLOAK_WILDFLY_USER_PROP, KEYCLOAK_ADMIN_USER); addEnv(KEYCLOAK_WILDFLY_PASSWORD_PROP, KEYCLOAK_ADMIN_PASSWORD); @@ -521,16 +525,32 @@ private void createRealm(String keycloakUrl, RealmRepresentation realm) { keycloakUrl + "/realms/master/protocol/openid-connect/token", "admin-cli", null, "admin", "admin", null, capturedDevServicesConfiguration.webClienTimeout); - HttpResponse response = client.postAbs(keycloakUrl + "/admin/realms") + HttpResponse createRealmResponse = client.postAbs(keycloakUrl + "/admin/realms") .putHeader(HttpHeaders.CONTENT_TYPE.toString(), "application/json") .putHeader(HttpHeaders.AUTHORIZATION.toString(), "Bearer " + token) .sendBuffer(Buffer.buffer().appendString(JsonSerialization.writeValueAsString(realm))) .await().atMost(capturedDevServicesConfiguration.webClienTimeout); - if (response.statusCode() > 299) { - LOG.errorf("Realm %s can not be created %d - %s ", realm.getRealm(), response.statusCode(), - response.statusMessage()); + if (createRealmResponse.statusCode() > 299) { + LOG.errorf("Realm %s can not be created %d - %s ", realm.getRealm(), createRealmResponse.statusCode(), + createRealmResponse.statusMessage()); } + + Uni realmStatusCodeUni = client.getAbs(keycloakUrl + "/realms/" + realm.getRealm()) + .send().onItem() + .transform(resp -> { + LOG.debugf("Realm status: %d", resp.statusCode()); + if (resp.statusCode() == 200) { + return 200; + } else { + throw new RealmEndpointAccessException(resp.statusCode()); + } + }).onFailure(realmEndpointNotAvailable()) + .retry() + .withBackOff(Duration.ofSeconds(2), Duration.ofSeconds(2)) + .expireIn(10 * 1000) + .onFailure().transform(t -> t.getCause()); + realmStatusCodeUni.await().atMost(Duration.ofSeconds(10)); } catch (Throwable t) { LOG.errorf("Realm %s can not be created: %s", realm.getRealm(), t.getMessage()); } finally { @@ -538,6 +558,24 @@ private void createRealm(String keycloakUrl, RealmRepresentation realm) { } } + @SuppressWarnings("serial") + static class RealmEndpointAccessException extends RuntimeException { + private final int errorStatus; + + public RealmEndpointAccessException(int errorStatus) { + this.errorStatus = errorStatus; + } + + public int getErrorStatus() { + return errorStatus; + } + } + + public static Predicate realmEndpointNotAvailable() { + return t -> (t instanceof ConnectException + || (t instanceof RealmEndpointAccessException && ((RealmEndpointAccessException) t).getErrorStatus() == 404)); + } + private Map getUsers(Map configuredUsers, boolean createRealm) { if (configuredUsers.isEmpty() && createRealm) { Map users = new LinkedHashMap();