diff --git a/doc/kubernetes/collector/build.sh b/doc/kubernetes/collector/build.sh index 258e26b23..36f79a862 100755 --- a/doc/kubernetes/collector/build.sh +++ b/doc/kubernetes/collector/build.sh @@ -15,6 +15,7 @@ helm template --debug ${STARTDIR}/../../../provision/minikube/keycloak \ --set keycloakHostname=\ \ --set dbUrl=\ \ --set keycloakImage=\ \ + --set useAWSJDBCWrapper=true \ --set jvmDebug=false \ --set cryostat=false \ --set instances=3 \ @@ -37,6 +38,7 @@ helm template --debug ${STARTDIR}/../../../provision/minikube/keycloak \ --set keycloakHostname=\ \ --set dbUrl=\ \ --set keycloakImage=\ \ + --set useAWSJDBCWrapper=true \ --set jvmDebug=false \ --set cryostat=false \ --set heapInitMB=64 \ diff --git a/provision/minikube/keycloak/config/kcb-infinispan-cache-remote-store-config.xml b/provision/minikube/keycloak/config/kcb-infinispan-cache-remote-store-config.xml index bdf643136..02b8ed425 100644 --- a/provision/minikube/keycloak/config/kcb-infinispan-cache-remote-store-config.xml +++ b/provision/minikube/keycloak/config/kcb-infinispan-cache-remote-store-config.xml @@ -53,6 +53,9 @@ raw-values="true" shared="true" segmented="false"> + + + "Embedded cache " + cache + " in DC1 has " + DC_1.ispn().cache(cache).size() + " entries"); + assertEquals(DC_2.kc().embeddedIspn().cache(cache).size(), size, () -> "Embedded cache " + cache + " in DC2 has " + DC_2.ispn().cache(cache).size() + " entries"); + + // External caches + assertEquals(DC_1.ispn().cache(cache).size(), size, () -> "External cache " + cache + " in DC1 has " + DC_1.ispn().cache(cache).size() + " entries"); + assertEquals(DC_2.ispn().cache(cache).size(), size, () -> "External cache " + cache + " in DC2 has " + DC_2.ispn().cache(cache).size() + " entries"); + } } diff --git a/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/LoginLogoutTest.java b/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/LoginLogoutTest.java index e2c85ae6f..daf591c7e 100644 --- a/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/LoginLogoutTest.java +++ b/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/LoginLogoutTest.java @@ -4,10 +4,12 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.net.http.HttpResponse; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.keycloak.benchmark.crossdc.util.InfinispanUtils.CLIENT_SESSIONS; import static org.keycloak.benchmark.crossdc.util.InfinispanUtils.SESSIONS; @@ -57,4 +59,25 @@ public void loginLogoutTest() throws URISyntaxException, IOException, Interrupte //Verify session cache size in embedded ISPN DC2 assertEquals(0, DC_2.kc().embeddedIspn().cache(SESSIONS).size()); } + + @Test + public void testRefreshTokenRevocation() throws Exception { + assertCacheSize(SESSIONS, 0); + assertCacheSize(CLIENT_SESSIONS, 0); + for (int i = 0; i < 20; i++) { + // Create a new user session + Map tokensMap = LOAD_BALANCER_KEYCLOAK.passwordGrant(REALM_NAME, CLIENTID, USERNAME, MAIN_PASSWORD); + assertCacheSize(SESSIONS, 1); + assertCacheSize(CLIENT_SESSIONS, 1); + + // Do the token revocation + HttpResponse stringHttpResponse = DC_1.kc().revokeRefreshToken(REALM_NAME, CLIENTID, (String) tokensMap.get("refresh_token")); + assertEquals(200, stringHttpResponse.statusCode()); + assertEquals("", stringHttpResponse.body()); + + // The revocation should clean all sessions + assertCacheSize(SESSIONS, 0); + assertCacheSize(CLIENT_SESSIONS, 0); + } + } } diff --git a/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/client/KeycloakClient.java b/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/client/KeycloakClient.java index b648dbe64..c941656c0 100644 --- a/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/client/KeycloakClient.java +++ b/provision/rosa-cross-dc/keycloak-benchmark-crossdc-tests/src/test/java/org/keycloak/benchmark/crossdc/client/KeycloakClient.java @@ -115,7 +115,46 @@ public Map exchangeCode(String realmName, String clientId, Strin return JsonSerialization.readValue(response.body(), Map.class); } + public Map passwordGrant(String realmName, String clientId, String username, String password) throws URISyntaxException, IOException, InterruptedException { + Map formData = new HashMap<>(); + formData.put("grant_type", "password"); + formData.put("username", username); + formData.put("password", password); + formData.put("client_id", clientId); + formData.put("scope", "openid profile"); + + HttpRequest request = HttpRequest.newBuilder() + .header("Content-Type", "application/x-www-form-urlencoded") + .uri(new URI(testRealmUrl(realmName) + "/protocol/openid-connect/token")) + .POST(HttpRequest.BodyPublishers.ofString(getFormDataAsString(formData))) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + return JsonSerialization.readValue(response.body(), Map.class); + } + + public HttpResponse revokeRefreshToken(String realmName, String clientId, String refreshToken) throws URISyntaxException, IOException, InterruptedException { + Map formData = new HashMap<>(); + formData.put("client_id", clientId); + formData.put("token", refreshToken); + + HttpRequest request = HttpRequest.newBuilder() + .header("Content-Type", "application/x-www-form-urlencoded") + .uri(new URI(testRealmUrl(realmName) + "/protocol/openid-connect/revoke")) + .POST(HttpRequest.BodyPublishers.ofString(getFormDataAsString(formData))) + .build(); + + return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + public Map refreshToken(String realmName, String refreshToken, String clientId, String clientSecret, int expectedReturnCode) throws URISyntaxException, IOException, InterruptedException { + HttpResponse response = refreshToken(realmName, refreshToken, clientId, clientSecret); + assertEquals(expectedReturnCode, response.statusCode()); + + return JsonSerialization.readValue(response.body(), Map.class); + } + + public HttpResponse refreshToken(String realmName, String refreshToken, String clientId, String clientSecret) throws URISyntaxException, IOException, InterruptedException { Map formData = new HashMap<>(); formData.put("grant_type", "refresh_token"); formData.put("refresh_token", refreshToken); @@ -129,10 +168,7 @@ public Map refreshToken(String realmName, String refreshToken, S .POST(HttpRequest.BodyPublishers.ofString(getFormDataAsString(formData))) .build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(expectedReturnCode, response.statusCode()); - - return JsonSerialization.readValue(response.body(), Map.class); + return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } public String usernamePasswordLogin(String realmName, String username, String password, String clientId) throws IOException, URISyntaxException, InterruptedException {