From e44c827e7071fa9977bf1a58b93aeb3a5a173a2c Mon Sep 17 00:00:00 2001 From: Lukas Hanusovsky Date: Thu, 12 Feb 2026 14:39:17 +0100 Subject: [PATCH] [Test Framework] Fix of AdminClientSupplier for ManagedRealm,ManagedUser and ManagedClient. Signed-off-by: Lukas Hanusovsky --- .../admin/AdminClientSupplier.java | 32 ++-- .../annotations/InjectAdminClient.java | 2 + .../test/examples/AdminClientTest.java | 154 ++++++++++++++++++ 3 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 test-framework/examples/tests/src/test/java/org/keycloak/test/examples/AdminClientTest.java diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/admin/AdminClientSupplier.java b/test-framework/core/src/main/java/org/keycloak/testframework/admin/AdminClientSupplier.java index 4922543a6149..e01b7822ec3d 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/admin/AdminClientSupplier.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/admin/AdminClientSupplier.java @@ -5,7 +5,6 @@ import org.keycloak.OAuth2Constants; import org.keycloak.admin.client.Keycloak; import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testframework.FatalTestClassException; import org.keycloak.testframework.annotations.InjectAdminClient; @@ -25,7 +24,10 @@ public class AdminClientSupplier implements Supplier getDependencies(RequestedInstance instanceContext) { DependenciesBuilder builder = DependenciesBuilder.create(AdminClientFactory.class); if (instanceContext.getAnnotation().mode().equals(InjectAdminClient.Mode.MANAGED_REALM)) { - builder.add(ManagedRealm.class); + builder.add(ManagedRealm.class, instanceContext.getAnnotation().realmRef()); + if (!instanceContext.getAnnotation().userRef().isEmpty()) { + builder.add(ManagedUser.class, instanceContext.getAnnotation().user()); + } } return builder.build(); } @@ -42,29 +44,39 @@ public Keycloak getValue(InstanceContext instanceCo if (mode.equals(InjectAdminClient.Mode.BOOTSTRAP)) { adminBuilder.realm("master").clientId(Config.getAdminClientId()).clientSecret(Config.getAdminClientSecret()); } else if (mode.equals(InjectAdminClient.Mode.MANAGED_REALM)) { - ManagedRealm managedRealm = instanceContext.getDependency(ManagedRealm.class); + ManagedRealm managedRealm = instanceContext.getDependency(ManagedRealm.class, instanceContext.getAnnotation().realmRef()); adminBuilder.realm(managedRealm.getName()); String clientId = !annotation.client().isEmpty() ? annotation.client() : null; String userId = !annotation.user().isEmpty() ? annotation.user() : null; + String userRef = !annotation.userRef().isEmpty() ? annotation.user() : null; if (clientId == null) { throw new FatalTestClassException("Client is required when using admin client in managed realm mode"); } - RealmRepresentation realmRep = managedRealm.getCreatedRepresentation(); - ClientRepresentation clientRep = realmRep.getClients().stream() + ClientRepresentation clientRep = managedRealm.admin().clients().findAll().stream() .filter(c -> c.getClientId().equals(annotation.client())) .findFirst().orElseThrow(() -> new FatalTestClassException("Client with clientId=\"" + annotation.client() + "\" not found in realm with ref=\"" + annotation.realmRef() + "\"")); adminBuilder.clientId(clientId).clientSecret(clientRep.getSecret()); if (userId != null) { - UserRepresentation userRep = realmRep.getUsers().stream() - .filter(u -> u.getUsername().equals(annotation.user())) - .findFirst().orElseThrow(() -> new FatalTestClassException("User with username=\"" + annotation.user() + "\" not found in realm with ref=\"" + annotation.realmRef() + "\"")); - String password = ManagedUser.getPassword(userRep); - adminBuilder.username(userRep.getUsername()).password(password); + String username = ""; + String password = ""; + + if (userRef != null) { + ManagedUser user = instanceContext.getDependency(ManagedUser.class, userRef); + username = user.getUsername(); + password = user.getPassword(); + } else { + UserRepresentation userRep = managedRealm.getCreatedRepresentation().getUsers().stream() + .filter(u -> u.getUsername().equals(annotation.user())) + .findFirst().orElseThrow(() -> new FatalTestClassException("User with username=\"" + annotation.user() + "\" not found in realm with ref=\"" + annotation.realmRef() + "\"")); + username = userRep.getUsername(); + password = ManagedUser.getPassword(userRep); + } + adminBuilder.username(username).password(password); adminBuilder.grantType(OAuth2Constants.PASSWORD); } } diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/annotations/InjectAdminClient.java b/test-framework/core/src/main/java/org/keycloak/testframework/annotations/InjectAdminClient.java index 4435f51066d2..01188ec2102f 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/annotations/InjectAdminClient.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/annotations/InjectAdminClient.java @@ -20,6 +20,8 @@ String user() default ""; + String userRef() default ""; + enum Mode { BOOTSTRAP, diff --git a/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/AdminClientTest.java b/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/AdminClientTest.java new file mode 100644 index 000000000000..4b6b8212ee49 --- /dev/null +++ b/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/AdminClientTest.java @@ -0,0 +1,154 @@ +package org.keycloak.test.examples; + +import java.util.List; + +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.NotAuthorizedException; + +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.models.AdminRoles; +import org.keycloak.models.Constants; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.testframework.annotations.InjectAdminClient; +import org.keycloak.testframework.annotations.InjectClient; +import org.keycloak.testframework.annotations.InjectEvents; +import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.annotations.InjectUser; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.events.EventAssertion; +import org.keycloak.testframework.events.Events; +import org.keycloak.testframework.realm.ClientConfig; +import org.keycloak.testframework.realm.ClientConfigBuilder; +import org.keycloak.testframework.realm.ManagedClient; +import org.keycloak.testframework.realm.ManagedRealm; +import org.keycloak.testframework.realm.ManagedUser; +import org.keycloak.testframework.realm.RealmConfig; +import org.keycloak.testframework.realm.RealmConfigBuilder; +import org.keycloak.testframework.realm.UserConfig; +import org.keycloak.testframework.realm.UserConfigBuilder; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@KeycloakIntegrationTest +public class AdminClientTest { + + @InjectRealm + ManagedRealm defaultRealm; + + @InjectRealm(ref = "customrealm", config = CustomRealmConf.class) + ManagedRealm customRealm; + + @InjectUser(ref = "myuser", config = MyUserConf.class) + ManagedUser myUser; + + @InjectUser(ref = "customuser", realmRef = "customrealm", config = CustomUserConf.class) + ManagedUser customUser; + + @InjectClient(ref = "myclient", config = MyClientConf.class) + ManagedClient myClient; + + @InjectClient(ref = "customclient", realmRef = "customrealm", config = CustomClientConf.class) + ManagedClient customClient; + + @InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, client = "myclient") + Keycloak adminClient; + + @InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, ref = "customclient", realmRef = "customrealm", client = "customclient") + Keycloak customAdminClient; + + @InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, ref = "myuser", user = "myuser", userRef = "myuser",client = "myclient") + Keycloak adminClientAsMyUser; + + @InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, ref = "customuser", realmRef = "customrealm", user = "customuser", userRef = "customuser",client = "customclient") + Keycloak adminClientAsCustomUser; + + @InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, ref = "realmuser", realmRef = "customrealm", user = "realmuser", client = "realmclient") + Keycloak adminClientAsRealmUser; + + @InjectEvents + Events defaultEvents; + + @InjectEvents(ref = "customevents", realmRef = "customrealm") + Events customEvents; + + @Test + public void testAdminClientWithNoAccessAsClient() { + Assertions.assertThrows(NotAuthorizedException.class, () -> adminClient.tokenManager().getAccessToken()); + EventAssertion.assertError(defaultEvents.poll()).clientId(myClient.getClientId()).error("invalid_client"); + Assertions.assertThrows(NotAuthorizedException.class, () -> customAdminClient.tokenManager().getAccessToken()); + EventAssertion.assertError(customEvents.poll()).clientId(customClient.getClientId()).error("invalid_client"); + } + + @Test + public void testAdminClientWithNoAccessAsUser() { + addRealmAdminClientRoleToUser(defaultRealm.admin(), myUser.getUsername()); + + Assertions.assertThrows(BadRequestException.class, () -> adminClientAsMyUser.tokenManager().getAccessToken().getToken().isEmpty()); + EventAssertion.assertError(defaultEvents.poll()).clientId(myClient.getClientId()).error("not_allowed"); + } + + @Test + public void testAdminClientWithAccessAsUser() { + String realmUsername = "realmuser"; + + addRealmAdminClientRoleToUser(customRealm.admin(), customUser.getUsername()); + + Assertions.assertFalse(adminClientAsRealmUser.tokenManager().getAccessToken().getToken().isEmpty()); + EventAssertion.assertSuccess(customEvents.poll()).details("username", realmUsername); + + Assertions.assertFalse(adminClientAsCustomUser.tokenManager().getAccessToken().getToken().isEmpty()); + EventAssertion.assertSuccess(customEvents.poll()).details("username", customUser.getUsername()); + } + + private void addRealmAdminClientRoleToUser(RealmResource realmResource, String username) { + UserRepresentation userRep = realmResource.users().search(username, true).get(0); + String realmMngId = realmResource.clients().findByClientId("realm-management").get(0).getId(); + List realmAdminRole = realmResource.users().get(userRep.getId()).roles() + .clientLevel(realmMngId).listAvailable().stream().filter(f -> f.getName().equals(AdminRoles.REALM_ADMIN)).toList(); + realmResource.users().get(userRep.getId()).roles().clientLevel(realmMngId).add(realmAdminRole); + } + + private static class CustomRealmConf implements RealmConfig { + @Override + public RealmConfigBuilder configure(RealmConfigBuilder realm) { + realm.addUser("realmuser") + .password("realmuser") + .name("Realm", "User").email("realm@user").emailVerified(true) + .clientRoles(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN); + realm.addClient("realmclient") + .secret("realmclientsecret").directAccessGrantsEnabled(true); + return realm; + } + } + + private static class MyUserConf implements UserConfig { + @Override + public UserConfigBuilder configure(UserConfigBuilder user) { + return user.username("myuser").password("myuser").name("My", "User").email("my@user").emailVerified(true); + } + } + + private static class CustomUserConf implements UserConfig { + @Override + public UserConfigBuilder configure(UserConfigBuilder user) { + return user.username("customuser").password("customuser").name("Custom", "User").email("custom@user").emailVerified(true); + } + } + + private static class MyClientConf implements ClientConfig { + @Override + public ClientConfigBuilder configure(ClientConfigBuilder client) { + return client.clientId("myclient").secret("mysecret"); + } + } + + private static class CustomClientConf implements ClientConfig { + @Override + public ClientConfigBuilder configure(ClientConfigBuilder client) { + return client.clientId("customclient").secret("customsecret").directAccessGrantsEnabled(true); + } + } +}