diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 682969eaedc60..3cb6c7d7d54b7 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -688,6 +688,11 @@
quarkus-test-oidc-server
${project.version}
+
+ io.quarkus
+ quarkus-test-keycloak-server
+ ${project.version}
+
io.quarkus
quarkus-oidc-deployment
diff --git a/integration-tests/oidc/pom.xml b/integration-tests/oidc/pom.xml
index 128e44baf488e..66065311383b2 100644
--- a/integration-tests/oidc/pom.xml
+++ b/integration-tests/oidc/pom.xml
@@ -37,6 +37,11 @@
+
+ io.quarkus
+ quarkus-test-keycloak-server
+ test
+
io.quarkus
quarkus-junit5
@@ -134,6 +139,7 @@
false
+ ${keycloak.docker.image}
${keycloak.ssl.url}
@@ -143,6 +149,7 @@
false
+ ${keycloak.docker.image}
${keycloak.ssl.url}
@@ -175,91 +182,6 @@
-
- docker-keycloak
-
-
- start-containers
-
-
-
- http://localhost:8180/auth
- https://localhost:8543/auth
-
-
-
-
- io.fabric8
- docker-maven-plugin
-
-
-
- ${keycloak.docker.image}
- quarkus-test-keycloak
-
-
- 8180:8080
- 8543:8443
-
-
- admin
- admin
-
-
- Keycloak:
- default
- cyan
-
-
-
-
- http://localhost:8180
-
-
-
-
-
-
- true
-
-
-
- docker-start
- compile
-
- stop
- start
-
-
-
- docker-stop
- post-integration-test
-
- stop
-
-
-
-
-
- org.codehaus.mojo
- exec-maven-plugin
-
-
- docker-prune
- generate-resources
-
- exec
-
-
- ${docker-prune.location}
-
-
-
-
-
-
-
-
diff --git a/integration-tests/oidc/src/main/resources/application.properties b/integration-tests/oidc/src/main/resources/application.properties
index 2a425123ef58e..bbeaa8b34ef8b 100644
--- a/integration-tests/oidc/src/main/resources/application.properties
+++ b/integration-tests/oidc/src/main/resources/application.properties
@@ -1,6 +1,6 @@
# Configuration file
quarkus.oidc.auth-server-url=${keycloak.ssl.url}/realms/quarkus/
-quarkus.oidc.client-id=quarkus-app
+quarkus.oidc.client-id=quarkus-service-app
quarkus.oidc.credentials.secret=secret
quarkus.oidc.token.principal-claim=email
quarkus.oidc.tls.verification=none
diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
index b5a88e6f7584d..af69812984c1a 100644
--- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
+++ b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
@@ -1,7 +1,7 @@
package io.quarkus.it.keycloak;
-import static io.quarkus.it.keycloak.KeycloakRealmResourceManager.getAccessToken;
-import static io.quarkus.it.keycloak.KeycloakRealmResourceManager.getRefreshToken;
+import static io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager.getAccessToken;
+import static io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager.getRefreshToken;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.equalTo;
@@ -16,13 +16,14 @@
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager;
import io.restassured.RestAssured;
/**
* @author Pedro Igor
*/
@QuarkusTest
-@QuarkusTestResource(KeycloakRealmResourceManager.class)
+@QuarkusTestResource(KeycloakTestResourceLifecycleManager.class)
public class BearerTokenAuthorizationTest {
@Test
diff --git a/test-framework/keycloak-server/pom.xml b/test-framework/keycloak-server/pom.xml
new file mode 100644
index 0000000000000..ccc211795dc24
--- /dev/null
+++ b/test-framework/keycloak-server/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ io.quarkus
+ quarkus-test-framework
+ 999-SNAPSHOT
+
+
+ quarkus-test-keycloak-server
+ Quarkus - Test Framework - Keycloak Server support
+
+
+ org.keycloak
+ keycloak-adapter-core
+
+
+ org.keycloak
+ keycloak-core
+
+
+ org.testcontainers
+ testcontainers
+
+
+ io.rest-assured
+ rest-assured
+
+
+ io.rest-assured
+ xml-path
+
+
+
+
+ io.quarkus
+ quarkus-test-common
+
+
+ org.testcontainers
+ testcontainers
+
+
+
+
diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/server/KeycloakTestResourceLifecycleManager.java
similarity index 65%
rename from integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java
rename to test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/server/KeycloakTestResourceLifecycleManager.java
index 4ab07adb2bf32..04c9de75e9b5c 100644
--- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java
+++ b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/server/KeycloakTestResourceLifecycleManager.java
@@ -1,9 +1,9 @@
-package io.quarkus.it.keycloak;
+package io.quarkus.test.keycloak.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -15,14 +15,20 @@
import org.keycloak.representations.idm.RolesRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.util.JsonSerialization;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import io.restassured.RestAssured;
-public class KeycloakRealmResourceManager implements QuarkusTestResourceLifecycleManager {
+public class KeycloakTestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager {
- private static final String KEYCLOAK_SERVER_URL = System.getProperty("keycloak.ssl.url", "https://localhost:8543/auth");
- private static final String KEYCLOAK_REALM = "quarkus";
+ private GenericContainer keycloak;
+
+ private static String KEYCLOAK_SERVER_URL;
+ private static final String KEYCLOAK_REALM = "quarkus-service-realm";
+ private static final String KEYCLOAK_DOCKER_IMAGE = System.getProperty("keycloak.docker.image",
+ "quay.io/keycloak/keycloak:12.0.4");
static {
RestAssured.useRelaxedHTTPSValidation();
@@ -30,14 +36,30 @@ public class KeycloakRealmResourceManager implements QuarkusTestResourceLifecycl
@Override
public Map start() {
+ keycloak = new GenericContainer(KEYCLOAK_DOCKER_IMAGE)
+ .withExposedPorts(8080, 8443)
+ .withEnv("DB_VENDOR", "H2")
+ .withEnv("KEYCLOAK_USER", "admin")
+ .withEnv("KEYCLOAK_PASSWORD", "admin")
+ .waitingFor(Wait.forHttp("/auth").forPort(8080));
+
+ keycloak.start();
+
+ KEYCLOAK_SERVER_URL = "https://localhost:" + keycloak.getMappedPort(8443) + "/auth";
RealmRepresentation realm = createRealm(KEYCLOAK_REALM);
+ postRealm(realm);
- realm.getClients().add(createClient("quarkus-app"));
- realm.getUsers().add(createUser("alice", "user"));
- realm.getUsers().add(createUser("admin", "user", "admin"));
- realm.getUsers().add(createUser("jdoe", "user", "confidential"));
+ RealmRepresentation webAppRealm = createWebAppRealm("quarkus-webapp-realm");
+ postRealm(webAppRealm);
+
+ Map conf = new HashMap<>();
+ conf.put("quarkus.oidc.auth-server-url", KEYCLOAK_SERVER_URL + "/realms/" + KEYCLOAK_REALM);
+ return conf;
+ }
+
+ private void postRealm(RealmRepresentation realm) {
try {
RestAssured
.given()
@@ -50,19 +72,6 @@ public Map start() {
} catch (IOException e) {
throw new RuntimeException(e);
}
- return Collections.emptyMap();
- }
-
- private static String getAdminAccessToken() {
- return RestAssured
- .given()
- .param("grant_type", "password")
- .param("username", "admin")
- .param("password", "admin")
- .param("client_id", "admin-cli")
- .when()
- .post(KEYCLOAK_SERVER_URL + "/realms/master/protocol/openid-connect/token")
- .as(AccessTokenResponse.class).getToken();
}
private static RealmRepresentation createRealm(String name) {
@@ -84,9 +93,54 @@ private static RealmRepresentation createRealm(String name) {
realm.getRoles().getRealm().add(new RoleRepresentation("admin", null, false));
realm.getRoles().getRealm().add(new RoleRepresentation("confidential", null, false));
+ realm.getClients().add(createClient("quarkus-service-app"));
+ realm.getUsers().add(createUser("alice", "user"));
+ realm.getUsers().add(createUser("admin", "user", "admin"));
+ realm.getUsers().add(createUser("jdoe", "user", "confidential"));
+
return realm;
}
+ private static RealmRepresentation createWebAppRealm(String name) {
+ RealmRepresentation realm = new RealmRepresentation();
+
+ realm.setRealm(name);
+ realm.setEnabled(true);
+ realm.setUsers(new ArrayList<>());
+ realm.setClients(new ArrayList<>());
+ realm.setSsoSessionMaxLifespan(3); // sec
+ realm.setAccessTokenLifespan(4); // 3 seconds
+
+ RolesRepresentation roles = new RolesRepresentation();
+ List realmRoles = new ArrayList<>();
+
+ roles.setRealm(realmRoles);
+ realm.setRoles(roles);
+
+ realm.getRoles().getRealm().add(new RoleRepresentation("user", null, false));
+ realm.getRoles().getRealm().add(new RoleRepresentation("admin", null, false));
+ realm.getRoles().getRealm().add(new RoleRepresentation("confidential", null, false));
+
+ realm.getClients().add(createClient("quarkus-app"));
+ realm.getUsers().add(createUser("alice", "user"));
+ realm.getUsers().add(createUser("admin", "user", "admin"));
+ realm.getUsers().add(createUser("jdoe", "user", "confidential"));
+
+ return realm;
+ }
+
+ private static String getAdminAccessToken() {
+ return RestAssured
+ .given()
+ .param("grant_type", "password")
+ .param("username", "admin")
+ .param("password", "admin")
+ .param("client_id", "admin-cli")
+ .when()
+ .post(KEYCLOAK_SERVER_URL + "/realms/master/protocol/openid-connect/token")
+ .as(AccessTokenResponse.class).getToken();
+ }
+
private static ClientRepresentation createClient(String clientId) {
ClientRepresentation client = new ClientRepresentation();
@@ -119,23 +173,13 @@ private static UserRepresentation createUser(String username, String... realmRol
return user;
}
- @Override
- public void stop() {
-
- RestAssured
- .given()
- .auth().oauth2(getAdminAccessToken())
- .when()
- .delete(KEYCLOAK_SERVER_URL + "/admin/realms/" + KEYCLOAK_REALM).then().statusCode(204);
- }
-
public static String getAccessToken(String userName) {
return RestAssured
.given()
.param("grant_type", "password")
.param("username", userName)
.param("password", userName)
- .param("client_id", "quarkus-app")
+ .param("client_id", "quarkus-service-app")
.param("client_secret", "secret")
.when()
.post(KEYCLOAK_SERVER_URL + "/realms/" + KEYCLOAK_REALM + "/protocol/openid-connect/token")
@@ -148,10 +192,23 @@ public static String getRefreshToken(String userName) {
.param("grant_type", "password")
.param("username", userName)
.param("password", userName)
- .param("client_id", "quarkus-app")
+ .param("client_id", "quarkus-service-app")
.param("client_secret", "secret")
.when()
.post(KEYCLOAK_SERVER_URL + "/realms/" + KEYCLOAK_REALM + "/protocol/openid-connect/token")
.as(AccessTokenResponse.class).getRefreshToken();
}
+
+ @Override
+ public void stop() {
+
+ RestAssured
+ .given()
+ .auth().oauth2(getAdminAccessToken())
+ .when()
+ .delete(KEYCLOAK_SERVER_URL + "/admin/realms/" + KEYCLOAK_REALM).then().statusCode(204);
+
+ keycloak.stop();
+ }
+
}
diff --git a/test-framework/pom.xml b/test-framework/pom.xml
index b245af38aa1c4..db2f816d0a165 100644
--- a/test-framework/pom.xml
+++ b/test-framework/pom.xml
@@ -37,6 +37,7 @@
ldap
security
oidc-server
+ keycloak-server
jacoco