From 3e5461403705282644d190ff78cb0de08bf64e70 Mon Sep 17 00:00:00 2001 From: Stephan Schnabel Date: Fri, 15 Sep 2023 11:43:28 +0200 Subject: [PATCH] Use java http client because keycloak api in incompatible --- .github/workflows/pr.yaml | 2 +- .../kokuwa/keycloak/metrics/KeycloakIT.java | 11 +-- .../metrics/junit/KeycloakClient.java | 74 ++++++++++++------- .../metrics/junit/KeycloakExtension.java | 2 +- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 8a17c98..009c366 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -49,7 +49,7 @@ jobs: version: - 21.0.2 - 21.1.2 - - 22.0.2 + - 22.0.3 steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/src/test/java/io/kokuwa/keycloak/metrics/KeycloakIT.java b/src/test/java/io/kokuwa/keycloak/metrics/KeycloakIT.java index 4475113..1eaa0b1 100644 --- a/src/test/java/io/kokuwa/keycloak/metrics/KeycloakIT.java +++ b/src/test/java/io/kokuwa/keycloak/metrics/KeycloakIT.java @@ -3,7 +3,7 @@ package io.kokuwa.keycloak.metrics; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Instant; @@ -18,6 +18,7 @@ import org.keycloak.events.EventType; import io.kokuwa.keycloak.metrics.junit.KeycloakClient; import io.kokuwa.keycloak.metrics.junit.KeycloakExtension; import io.kokuwa.keycloak.metrics.junit.Prometheus; +import jakarta.ws.rs.NotAuthorizedException; /** * Integration tests with Keycloak. @@ -55,10 +56,10 @@ public class KeycloakIT { var loginErrorBefore1 = prometheus.userEvent(EventType.LOGIN_ERROR, realmName1, clientId1); var loginErrorBefore2 = prometheus.userEvent(EventType.LOGIN_ERROR, realmName2, clientId2); - assertTrue(keycloak.login(clientId1, realmName1, username1, password1)); - assertTrue(keycloak.login(clientId1, realmName1, username1, password1)); - assertTrue(keycloak.login(clientId2, realmName2, username2, password2)); - assertFalse(keycloak.login(clientId2, realmName2, username2, "nope")); + assertDoesNotThrow(() -> keycloak.login(clientId1, realmName1, username1, password1)); + assertDoesNotThrow(() -> keycloak.login(clientId1, realmName1, username1, password1)); + assertDoesNotThrow(() -> keycloak.login(clientId2, realmName2, username2, password2)); + assertThrows(NotAuthorizedException.class, () -> keycloak.login(clientId2, realmName2, username2, "nope")); prometheus.scrap(); var loginAfter = prometheus.userEvent(EventType.LOGIN); diff --git a/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakClient.java b/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakClient.java index 098516d..9f66fbd 100644 --- a/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakClient.java +++ b/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakClient.java @@ -1,7 +1,14 @@ package io.kokuwa.keycloak.metrics.junit; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse.BodyHandlers; import java.util.List; import java.util.Map; import java.util.UUID; @@ -9,12 +16,16 @@ import java.util.UUID; import org.keycloak.OAuth2Constants; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.token.TokenService; +import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; -import jakarta.ws.rs.NotAuthorizedException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedHashMap; /** @@ -25,11 +36,18 @@ import jakarta.ws.rs.core.MultivaluedHashMap; public class KeycloakClient { private final Keycloak keycloak; - private final TokenService token; + private final TokenService tokenService; - KeycloakClient(Keycloak keycloak, TokenService token) { + private final ObjectMapper mapper = new ObjectMapper(); + private final HttpClient client = HttpClient.newHttpClient(); + private final String url; + private final String adminToken; + + KeycloakClient(String url, Keycloak keycloak, TokenService tokenService) { this.keycloak = keycloak; - this.token = token; + this.tokenService = tokenService; + this.url = url; + this.adminToken = login("admin-cli", "master", "admin", "password").getToken(); } public void createRealm(String realmName) { @@ -52,18 +70,25 @@ public class KeycloakClient { } public void createUser(String realmName, String username, String password) { - var credential = new CredentialRepresentation(); - credential.setType(CredentialRepresentation.PASSWORD); - credential.setValue(password); - credential.setTemporary(false); - var user = new UserRepresentation(); - user.setEnabled(true); - user.setEmail(username + "@example.org"); - user.setEmailVerified(true); - user.setUsername(username); - user.setCredentials(List.of(credential)); - var response = keycloak.realms().realm(realmName).users().create(user); - assertEquals(201, response.getStatus()); + try { + var response = client.send(HttpRequest.newBuilder() + .uri(URI.create(url + "/admin/realms/" + realmName + "/users")) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .POST(BodyPublishers.ofString(mapper.writeValueAsString(Map.of( + "enabled", true, + "emailVerified", true, + "email", username + "@example.org", + "username", username, + "credentials", List.of(Map.of( + "type", CredentialRepresentation.PASSWORD, + "value", password, + "temporary", false)))))) + .build(), BodyHandlers.ofString()); + assertEquals(201, response.statusCode(), "Body: " + response.body()); + } catch (IOException | InterruptedException e) { + fail("Failed to create user", e); + } } public void deleteUser(String realmName, String username) { @@ -73,16 +98,11 @@ public class KeycloakClient { .forEach(keycloak.realms().realm(realmName).users()::delete); } - public boolean login(String clientId, String realmName, String username, String password) { - try { - token.grantToken(realmName, new MultivaluedHashMap<>(Map.of( - OAuth2Constants.CLIENT_ID, clientId, - OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD, - OAuth2Constants.USERNAME, username, - OAuth2Constants.PASSWORD, password))); - return true; - } catch (NotAuthorizedException e) { - return false; - } + public AccessTokenResponse login(String clientId, String realmName, String username, String password) { + return tokenService.grantToken(realmName, new MultivaluedHashMap<>(Map.of( + OAuth2Constants.CLIENT_ID, clientId, + OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD, + OAuth2Constants.USERNAME, username, + OAuth2Constants.PASSWORD, password))); } } diff --git a/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakExtension.java b/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakExtension.java index 729bd9b..c06c8f3 100644 --- a/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakExtension.java +++ b/src/test/java/io/kokuwa/keycloak/metrics/junit/KeycloakExtension.java @@ -80,7 +80,7 @@ public class KeycloakExtension implements BeforeAllCallback, ParameterResolver { var target = ClientBuilder.newClient().target(url); var token = Keycloak.getClientProvider().targetProxy(target, TokenService.class); prometheus = new Prometheus(Keycloak.getClientProvider().targetProxy(target, PrometheusClient.class)); - client = new KeycloakClient(keycloak, token); + client = new KeycloakClient(url, keycloak, token); } @Override