From f983e20109458bd556c18f6398660056b7c3b4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Fri, 8 Nov 2024 16:06:21 +0100 Subject: [PATCH] Start Keycloak Dev Svc for standalone KC Admin client --- .../KeycloakDevServicesConfigurator.java | 3 +- .../KeycloakDevServicesProcessor.java | 28 ++++++---- .../common/KeycloakAdminClientConfig.java | 7 +-- .../deployment/pom.xml | 9 ++-- .../KeycloakDevServiceRequiredBuildStep.java | 32 +++++++++++ ...akAdminClientInjectionDevServicesTest.java | 12 +++-- ...akAdminClientMutualTlsDevServicesTest.java | 12 +++-- ...kAdminClientZeroConfigDevServicesTest.java | 53 +++++++++++++++++++ .../resources/app-dev-mode-config.properties | 1 - .../deployment/pom.xml | 9 ++-- .../KeycloakDevServiceRequiredBuildStep.java | 32 +++++++++++ ...akAdminClientInjectionDevServicesTest.java | 12 +++-- ...akAdminClientMutualTlsDevServicesTest.java | 12 +++-- ...kAdminClientZeroConfigDevServicesTest.java | 53 +++++++++++++++++++ .../resources/app-dev-mode-config.properties | 1 - 15 files changed, 239 insertions(+), 37 deletions(-) create mode 100644 extensions/keycloak-admin-rest-client/deployment/src/main/java/io/quarkus/keycloak/admin/client/reactive/devservices/KeycloakDevServiceRequiredBuildStep.java create mode 100644 extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientZeroConfigDevServicesTest.java create mode 100644 extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/devservices/KeycloakDevServiceRequiredBuildStep.java create mode 100644 extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientZeroConfigDevServicesTest.java diff --git a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesConfigurator.java b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesConfigurator.java index a06f5df1a14b9..eff7e67bea529 100644 --- a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesConfigurator.java +++ b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesConfigurator.java @@ -6,7 +6,8 @@ public interface KeycloakDevServicesConfigurator { - record ConfigPropertiesContext(String authServerInternalUrl, String oidcClientId, String oidcClientSecret) { + record ConfigPropertiesContext(String authServerInternalUrl, String oidcClientId, String oidcClientSecret, + String authServerInternalBaseUrl) { } Map createProperties(ConfigPropertiesContext context); diff --git a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java index f366769ad048b..6663e45f3e8b4 100644 --- a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -287,14 +287,22 @@ private static void closeDevService() { capturedDevServicesConfiguration = null; } + private static String getBaseURL(String scheme, String host, Integer port) { + return scheme + host + ":" + port; + } + private static String startURL(String scheme, String host, Integer port, boolean isKeycloakX) { - return scheme + host + ":" + port + (isKeycloakX ? "" : "/auth"); + return getBaseURL(scheme, host, port) + (isKeycloakX ? "" : "/auth"); + } + + private static String startURL(String baseUrl, boolean isKeycloakX) { + return baseUrl + (isKeycloakX ? "" : "/auth"); } private static Map prepareConfiguration( BuildProducer keycloakBuildItemBuildProducer, String internalURL, String hostURL, List realmReps, List errors, - KeycloakDevServicesConfigurator devServicesConfigurator) { + KeycloakDevServicesConfigurator devServicesConfigurator, String internalBaseUrl) { final String realmName = realmReps != null && !realmReps.isEmpty() ? realmReps.iterator().next().getRealm() : getDefaultRealmName(); final String authServerInternalUrl = realmsURL(internalURL, realmName); @@ -338,7 +346,8 @@ private static Map prepareConfiguration( } Map configProperties = new HashMap<>(); - var configPropertiesContext = new ConfigPropertiesContext(authServerInternalUrl, oidcClientId, oidcClientSecret); + var configPropertiesContext = new ConfigPropertiesContext(authServerInternalUrl, oidcClientId, oidcClientSecret, + internalBaseUrl); configProperties.putAll(devServicesConfigurator.createProperties(configPropertiesContext)); configProperties.put(KEYCLOAK_URL_KEY, internalURL); configProperties.put(CLIENT_AUTH_SERVER_URL_CONFIG_KEY, clientAuthServerUrl); @@ -397,8 +406,9 @@ private static RunningDevService startContainer( oidcContainer.withEnv(capturedDevServicesConfiguration.containerEnv()); oidcContainer.start(); - String internalUrl = startURL((oidcContainer.isHttps() ? "https://" : "http://"), oidcContainer.getHost(), - oidcContainer.getPort(), oidcContainer.keycloakX); + String internalBaseUrl = getBaseURL((oidcContainer.isHttps() ? "https://" : "http://"), oidcContainer.getHost(), + oidcContainer.getPort()); + String internalUrl = startURL(internalBaseUrl, oidcContainer.keycloakX); String hostUrl = oidcContainer.useSharedNetwork // we need to use auto-detected host and port, so it works when docker host != localhost ? startURL("http://", oidcContainer.getSharedNetworkExternalHost(), @@ -407,7 +417,7 @@ private static RunningDevService startContainer( : null; Map configs = prepareConfiguration(keycloakBuildItemBuildProducer, internalUrl, hostUrl, - oidcContainer.realmReps, errors, devServicesConfigurator); + oidcContainer.realmReps, errors, devServicesConfigurator, internalBaseUrl); return new RunningDevService(KEYCLOAK_CONTAINER_NAME, oidcContainer.getContainerId(), oidcContainer::close, configs); }; @@ -415,9 +425,9 @@ private static RunningDevService startContainer( return maybeContainerAddress .map(containerAddress -> { // TODO: this probably needs to be addressed - Map configs = prepareConfiguration(keycloakBuildItemBuildProducer, - getSharedContainerUrl(containerAddress), - getSharedContainerUrl(containerAddress), null, errors, devServicesConfigurator); + String sharedContainerUrl = getSharedContainerUrl(containerAddress); + Map configs = prepareConfiguration(keycloakBuildItemBuildProducer, sharedContainerUrl, + sharedContainerUrl, null, errors, devServicesConfigurator, sharedContainerUrl); return new RunningDevService(KEYCLOAK_CONTAINER_NAME, containerAddress.getId(), null, configs); }) .orElseGet(defaultKeycloakContainerSupplier); diff --git a/extensions/keycloak-admin-client-common/runtime/src/main/java/io/quarkus/keycloak/admin/client/common/KeycloakAdminClientConfig.java b/extensions/keycloak-admin-client-common/runtime/src/main/java/io/quarkus/keycloak/admin/client/common/KeycloakAdminClientConfig.java index 004200936b2bd..aab53d23fda50 100644 --- a/extensions/keycloak-admin-client-common/runtime/src/main/java/io/quarkus/keycloak/admin/client/common/KeycloakAdminClientConfig.java +++ b/extensions/keycloak-admin-client-common/runtime/src/main/java/io/quarkus/keycloak/admin/client/common/KeycloakAdminClientConfig.java @@ -16,9 +16,10 @@ public interface KeycloakAdminClientConfig { /** * Keycloak server URL, for example, `https://host:port`. - * If this property is not set then the Keycloak Admin Client injection will fail - use - * {@linkplain org.keycloak.admin.client.KeycloakBuilder} - * to create it instead. + * When the Keycloak Dev Services is started and this property is not configured, + * Quarkus points the 'quarkus.keycloak.admin-client.server-url' configuration property to started Keycloak container. + * In other cases, when this property is not set then the Keycloak Admin Client injection will fail - use + * {@linkplain org.keycloak.admin.client.KeycloakBuilder} to create the client instead. */ Optional serverUrl(); diff --git a/extensions/keycloak-admin-rest-client/deployment/pom.xml b/extensions/keycloak-admin-rest-client/deployment/pom.xml index 8ff302c1ac65f..32d5c33b5db81 100644 --- a/extensions/keycloak-admin-rest-client/deployment/pom.xml +++ b/extensions/keycloak-admin-rest-client/deployment/pom.xml @@ -29,6 +29,10 @@ io.quarkus quarkus-keycloak-admin-client-common-deployment + + io.quarkus + quarkus-devservices-keycloak + io.quarkus @@ -45,11 +49,6 @@ quarkus-rest-jackson-deployment test - - io.quarkus - quarkus-oidc-deployment - test - io.smallrye.certs smallrye-certificate-generator-junit5 diff --git a/extensions/keycloak-admin-rest-client/deployment/src/main/java/io/quarkus/keycloak/admin/client/reactive/devservices/KeycloakDevServiceRequiredBuildStep.java b/extensions/keycloak-admin-rest-client/deployment/src/main/java/io/quarkus/keycloak/admin/client/reactive/devservices/KeycloakDevServiceRequiredBuildStep.java new file mode 100644 index 0000000000000..1d798dda51593 --- /dev/null +++ b/extensions/keycloak-admin-rest-client/deployment/src/main/java/io/quarkus/keycloak/admin/client/reactive/devservices/KeycloakDevServiceRequiredBuildStep.java @@ -0,0 +1,32 @@ +package io.quarkus.keycloak.admin.client.reactive.devservices; + +import java.util.Map; + +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.IsNormal; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig; +import io.quarkus.devservices.keycloak.KeycloakAdminPageBuildItem; +import io.quarkus.devservices.keycloak.KeycloakDevServicesRequiredBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.keycloak.admin.client.common.KeycloakAdminClientInjectionEnabled; + +@BuildSteps(onlyIfNot = IsNormal.class, onlyIf = { GlobalDevServicesConfig.Enabled.class, + KeycloakAdminClientInjectionEnabled.class }) +public class KeycloakDevServiceRequiredBuildStep { + + private static final String SERVER_URL_CONFIG_KEY = "quarkus.keycloak.admin-client.server-url"; + + @BuildStep + KeycloakDevServicesRequiredBuildItem requireKeycloakDevService() { + return KeycloakDevServicesRequiredBuildItem.of( + ctx -> Map.of(SERVER_URL_CONFIG_KEY, ctx.authServerInternalBaseUrl()), + SERVER_URL_CONFIG_KEY); + } + + @BuildStep(onlyIf = IsDevelopment.class) + KeycloakAdminPageBuildItem addCardWithLinkToKeycloakAdmin() { + return new KeycloakAdminPageBuildItem(new CardPageBuildItem()); + } +} diff --git a/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientInjectionDevServicesTest.java b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientInjectionDevServicesTest.java index b2c20096410c6..1551f3dfb1577 100644 --- a/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientInjectionDevServicesTest.java +++ b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientInjectionDevServicesTest.java @@ -15,17 +15,23 @@ import org.keycloak.admin.client.Keycloak; import org.keycloak.representations.idm.RoleRepresentation; -import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.builder.Version; +import io.quarkus.maven.dependency.Dependency; +import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; import io.restassured.response.Response; public class KeycloakAdminClientInjectionDevServicesTest { @RegisterExtension - final static QuarkusDevModeTest app = new QuarkusDevModeTest() + final static QuarkusUnitTest app = new QuarkusUnitTest() .withApplicationRoot(jar -> jar .addClasses(AdminResource.class) - .addAsResource("app-dev-mode-config.properties", "application.properties")); + .addAsResource("app-dev-mode-config.properties", "application.properties")) + // intention of this forced dependency is to test backwards compatibility + // when users started Keycloak Dev Service by adding OIDC extension and configured 'server-url' + .setForcedDependencies( + List.of(Dependency.of("io.quarkus", "quarkus-oidc-deployment", Version.getVersion()))); @Test public void testGetRoles() { diff --git a/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientMutualTlsDevServicesTest.java b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientMutualTlsDevServicesTest.java index 01542b0770234..753eabfe19bc3 100644 --- a/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientMutualTlsDevServicesTest.java +++ b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientMutualTlsDevServicesTest.java @@ -18,7 +18,9 @@ import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RolesRepresentation; -import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.builder.Version; +import io.quarkus.maven.dependency.Dependency; +import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; import io.smallrye.certs.Format; import io.smallrye.certs.junit5.Certificate; @@ -29,14 +31,18 @@ public class KeycloakAdminClientMutualTlsDevServicesTest { @RegisterExtension - final static QuarkusDevModeTest app = new QuarkusDevModeTest() + final static QuarkusUnitTest app = new QuarkusUnitTest() .withApplicationRoot(jar -> jar .addClasses(MtlsResource.class) .addAsResource(new File("target/certs/mtls-test-keystore.p12"), "server-keystore.p12") .addAsResource(new File("target/certs/mtls-test-server-ca.crt"), "server-ca.crt") .addAsResource(new File("target/certs/mtls-test-client-keystore.p12"), "client-keystore.p12") .addAsResource(new File("target/certs/mtls-test-client-truststore.p12"), "client-truststore.p12") - .addAsResource("app-mtls-config.properties", "application.properties")); + .addAsResource("app-mtls-config.properties", "application.properties")) + // intention of this forced dependency is to test backwards compatibility + // when users started Keycloak Dev Service by adding OIDC extension and configured 'server-url' + .setForcedDependencies( + List.of(Dependency.of("io.quarkus", "quarkus-oidc-deployment", Version.getVersion()))); @Test public void testCreateRealm() { diff --git a/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientZeroConfigDevServicesTest.java b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientZeroConfigDevServicesTest.java new file mode 100644 index 0000000000000..fe3853598015a --- /dev/null +++ b/extensions/keycloak-admin-rest-client/deployment/src/test/java/io/quarkus/keycloak/admin/client/reactive/KeycloakAdminClientZeroConfigDevServicesTest.java @@ -0,0 +1,53 @@ +package io.quarkus.keycloak.admin.client.reactive; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.representations.idm.RoleRepresentation; + +import io.quarkus.test.QuarkusDevModeTest; +import io.restassured.RestAssured; +import io.restassured.response.Response; + +public class KeycloakAdminClientZeroConfigDevServicesTest { + + @RegisterExtension + final static QuarkusDevModeTest app = new QuarkusDevModeTest() + .withApplicationRoot(jar -> jar.addClasses(AdminResource.class)); + + @Test + public void testGetRoles() { + // use 'password' grant type + final Response getRolesReq = RestAssured.given().get("/api/admin/roles"); + assertEquals(200, getRolesReq.statusCode()); + final List roles = getRolesReq.jsonPath().getList(".", RoleRepresentation.class); + assertNotNull(roles); + // assert there are roles admin and user (among others) + assertTrue(roles.stream().anyMatch(rr -> "user".equals(rr.getName()))); + assertTrue(roles.stream().anyMatch(rr -> "admin".equals(rr.getName()))); + } + + @Path("/api/admin") + public static class AdminResource { + + @Inject + Keycloak keycloak; + + @GET + @Path("/roles") + public List getRoles() { + return keycloak.realm("quarkus").roles().list(); + } + + } +} diff --git a/extensions/keycloak-admin-rest-client/deployment/src/test/resources/app-dev-mode-config.properties b/extensions/keycloak-admin-rest-client/deployment/src/test/resources/app-dev-mode-config.properties index 47e6f9633d8e6..ab1a9dac13289 100644 --- a/extensions/keycloak-admin-rest-client/deployment/src/test/resources/app-dev-mode-config.properties +++ b/extensions/keycloak-admin-rest-client/deployment/src/test/resources/app-dev-mode-config.properties @@ -2,5 +2,4 @@ quarkus.keycloak.devservices.port=8082 # Configure Keycloak Admin Client -quarkus.keycloak.admin-client=true quarkus.keycloak.admin-client.server-url=http://localhost:${quarkus.keycloak.devservices.port} diff --git a/extensions/keycloak-admin-resteasy-client/deployment/pom.xml b/extensions/keycloak-admin-resteasy-client/deployment/pom.xml index 882b34d8c8230..598684441f300 100644 --- a/extensions/keycloak-admin-resteasy-client/deployment/pom.xml +++ b/extensions/keycloak-admin-resteasy-client/deployment/pom.xml @@ -37,6 +37,10 @@ io.quarkus quarkus-keycloak-admin-client-common-deployment + + io.quarkus + quarkus-devservices-keycloak + io.quarkus @@ -53,11 +57,6 @@ quarkus-resteasy-jackson-deployment test - - io.quarkus - quarkus-oidc-deployment - test - io.smallrye.certs smallrye-certificate-generator-junit5 diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/devservices/KeycloakDevServiceRequiredBuildStep.java b/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/devservices/KeycloakDevServiceRequiredBuildStep.java new file mode 100644 index 0000000000000..1d330fa8b9ded --- /dev/null +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/devservices/KeycloakDevServiceRequiredBuildStep.java @@ -0,0 +1,32 @@ +package io.quarkus.keycloak.adminclient.deployment.devservices; + +import java.util.Map; + +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.IsNormal; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig; +import io.quarkus.devservices.keycloak.KeycloakAdminPageBuildItem; +import io.quarkus.devservices.keycloak.KeycloakDevServicesRequiredBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.keycloak.admin.client.common.KeycloakAdminClientInjectionEnabled; + +@BuildSteps(onlyIfNot = IsNormal.class, onlyIf = { GlobalDevServicesConfig.Enabled.class, + KeycloakAdminClientInjectionEnabled.class }) +public class KeycloakDevServiceRequiredBuildStep { + + private static final String SERVER_URL_CONFIG_KEY = "quarkus.keycloak.admin-client.server-url"; + + @BuildStep + KeycloakDevServicesRequiredBuildItem requireKeycloakDevService() { + return KeycloakDevServicesRequiredBuildItem.of( + ctx -> Map.of(SERVER_URL_CONFIG_KEY, ctx.authServerInternalBaseUrl()), + SERVER_URL_CONFIG_KEY); + } + + @BuildStep(onlyIf = IsDevelopment.class) + KeycloakAdminPageBuildItem addCardWithLinkToKeycloakAdmin() { + return new KeycloakAdminPageBuildItem(new CardPageBuildItem()); + } +} diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientInjectionDevServicesTest.java b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientInjectionDevServicesTest.java index 023213d4b211b..a87d149b61ca5 100644 --- a/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientInjectionDevServicesTest.java +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientInjectionDevServicesTest.java @@ -15,17 +15,23 @@ import org.keycloak.admin.client.Keycloak; import org.keycloak.representations.idm.RoleRepresentation; -import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.builder.Version; +import io.quarkus.maven.dependency.Dependency; +import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; import io.restassured.response.Response; public class KeycloakAdminClientInjectionDevServicesTest { @RegisterExtension - final static QuarkusDevModeTest app = new QuarkusDevModeTest() + final static QuarkusUnitTest app = new QuarkusUnitTest() .withApplicationRoot(jar -> jar .addClasses(AdminResource.class) - .addAsResource("app-dev-mode-config.properties", "application.properties")); + .addAsResource("app-dev-mode-config.properties", "application.properties")) + // intention of this forced dependency is to test backwards compatibility + // when users started Keycloak Dev Service by adding OIDC extension and configured 'server-url' + .setForcedDependencies( + List.of(Dependency.of("io.quarkus", "quarkus-oidc-deployment", Version.getVersion()))); @Test public void testGetRoles() { diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientMutualTlsDevServicesTest.java b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientMutualTlsDevServicesTest.java index b628adb65aed5..33eaac20f98ad 100644 --- a/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientMutualTlsDevServicesTest.java +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientMutualTlsDevServicesTest.java @@ -18,7 +18,9 @@ import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RolesRepresentation; -import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.builder.Version; +import io.quarkus.maven.dependency.Dependency; +import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; import io.smallrye.certs.Format; import io.smallrye.certs.junit5.Certificate; @@ -29,14 +31,18 @@ public class KeycloakAdminClientMutualTlsDevServicesTest { @RegisterExtension - final static QuarkusDevModeTest app = new QuarkusDevModeTest() + final static QuarkusUnitTest app = new QuarkusUnitTest() .withApplicationRoot(jar -> jar .addClasses(MtlsResource.class) .addAsResource(new File("target/certs/mtls-test-keystore.p12"), "server-keystore.p12") .addAsResource(new File("target/certs/mtls-test-server-ca.crt"), "server-ca.crt") .addAsResource(new File("target/certs/mtls-test-client-keystore.p12"), "client-keystore.p12") .addAsResource(new File("target/certs/mtls-test-client-truststore.p12"), "client-truststore.p12") - .addAsResource("app-mtls-config.properties", "application.properties")); + .addAsResource("app-mtls-config.properties", "application.properties")) + // intention of this forced dependency is to test backwards compatibility + // when users started Keycloak Dev Service by adding OIDC extension and configured 'server-url' + .setForcedDependencies( + List.of(Dependency.of("io.quarkus", "quarkus-oidc-deployment", Version.getVersion()))); @Test public void testCreateRealm() { diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientZeroConfigDevServicesTest.java b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientZeroConfigDevServicesTest.java new file mode 100644 index 0000000000000..440ed7514621d --- /dev/null +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/test/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientZeroConfigDevServicesTest.java @@ -0,0 +1,53 @@ +package io.quarkus.keycloak.adminclient.deployment; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.representations.idm.RoleRepresentation; + +import io.quarkus.test.QuarkusDevModeTest; +import io.restassured.RestAssured; +import io.restassured.response.Response; + +public class KeycloakAdminClientZeroConfigDevServicesTest { + + @RegisterExtension + final static QuarkusDevModeTest app = new QuarkusDevModeTest() + .withApplicationRoot(jar -> jar.addClasses(AdminResource.class)); + + @Test + public void testGetRoles() { + // use 'password' grant type + final Response getRolesReq = RestAssured.given().get("/api/admin/roles"); + assertEquals(200, getRolesReq.statusCode()); + final List roles = getRolesReq.jsonPath().getList(".", RoleRepresentation.class); + assertNotNull(roles); + // assert there are roles admin and user (among others) + assertTrue(roles.stream().anyMatch(rr -> "user".equals(rr.getName()))); + assertTrue(roles.stream().anyMatch(rr -> "admin".equals(rr.getName()))); + } + + @Path("/api/admin") + public static class AdminResource { + + @Inject + Keycloak keycloak; + + @GET + @Path("/roles") + public List getRoles() { + return keycloak.realm("quarkus").roles().list(); + } + + } +} diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/test/resources/app-dev-mode-config.properties b/extensions/keycloak-admin-resteasy-client/deployment/src/test/resources/app-dev-mode-config.properties index 47e6f9633d8e6..ab1a9dac13289 100644 --- a/extensions/keycloak-admin-resteasy-client/deployment/src/test/resources/app-dev-mode-config.properties +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/test/resources/app-dev-mode-config.properties @@ -2,5 +2,4 @@ quarkus.keycloak.devservices.port=8082 # Configure Keycloak Admin Client -quarkus.keycloak.admin-client=true quarkus.keycloak.admin-client.server-url=http://localhost:${quarkus.keycloak.devservices.port}