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/pom.xml b/pom.xml
index 867db42..e8dffba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
- 22.0.2
+ 22.0.3
${version.org.keycloak}
1.18.3
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