diff --git a/README.adoc b/README.adoc index c5a2a36..0320118 100644 --- a/README.adoc +++ b/README.adoc @@ -659,6 +659,8 @@ curl -s -X GET 'http://localhost:8090/auth/admin/realms/trikorasolutions/users/c } } ---- +Create realm role +curl -X POST "http://localhost:8090/auth/admin/realms/trikorasolutions/roles" -H "Content-Type: application/json" -H "Authorization: Bearer ${TKN}" -d '{"name": "test-role2"}' | jq . == Tokens (example with different credential types) diff --git a/src/main/java/com/trikorasolutions/keycloak/client/bl/KeycloakClientLogic.java b/src/main/java/com/trikorasolutions/keycloak/client/bl/KeycloakClientLogic.java index f813515..7a3bd62 100644 --- a/src/main/java/com/trikorasolutions/keycloak/client/bl/KeycloakClientLogic.java +++ b/src/main/java/com/trikorasolutions/keycloak/client/bl/KeycloakClientLogic.java @@ -10,6 +10,7 @@ import io.restassured.RestAssured; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.groups.UniJoin.Builder; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.jboss.resteasy.reactive.ClientWebApplicationException; import org.keycloak.representations.AccessTokenResponse; @@ -34,6 +35,9 @@ public class KeycloakClientLogic { private static final String GRANT_TYPE = "implicit"; private static final String GRANT_TYPE_PS = "password"; + @ConfigProperty(name = "trikora.keycloak.buffer-size") + private Integer KC_BUFFER_SIZE; + @RestClient KeycloakAuthAdminResource keycloakClient; @@ -51,7 +55,7 @@ public class KeycloakClientLogic { */ public Uni getTokenForUser(final String realm, final String keycloakClientId, final String secret) { - LOGGER.info("Getting token with params [realm: {}, client_id: {}]", realm, keycloakClientId); + LOGGER.debug("Getting token with params [realm: {}, client_id: {}]", realm, keycloakClientId); final String tok = RestAssured.given() .param("grant_type", "client_credentials") .param("client_id", keycloakClientId) @@ -230,8 +234,8 @@ public Uni deleteUser(final String realm, final String token, /** * This method return a list with all the users in the client provided as argument. It makes use - * of the first and the max params, in order to paginate the search. Making recursion with the - * mutiny, will subscribe the events sequentially. + * of the Keycloak first and the max params, in order to paginate the search. Making recursion + * with the mutiny, will subscribe the events sequentially. * * @param realm the realm name in which the users are going to be queried. * @param token access token provided by the keycloak SecurityIdentity. @@ -240,47 +244,45 @@ public Uni deleteUser(final String realm, final String token, */ public Uni> listAllUsers(final String realm, final String token, final String keycloakClientId) { - return this.listAllUsers(realm, token, keycloakClientId, Integer.MAX_VALUE); - // Keycloak di not allow to have more than (Int32) users, so Integer.MAX_VALUE would not - // imitate the search + return this.listAllUsersRec(realm, token, keycloakClientId, 0, Integer.MAX_VALUE, + new ArrayList<>()); } /** - * This method return a list with all the users in the client provided as argument. It makes use - * of the first and the max params, in order to paginate the search. Making recursion with the - * mutiny, will subscribe the events sequentially. + * This method return a list with the users in the client provided as argument. It makes use of + * the Keycloak first and the max params, in order to paginate the search. This method is useful + * to paginate the users * * @param realm the realm name in which the users are going to be queried. * @param token access token provided by the keycloak SecurityIdentity. * @param keycloakClientId id of the client (service name). - * @param maxUsers maximum number of users that are desired to be queried. It has to be a - * multiple of bufferSize that ATTOW is 100. + * @param first first user to be fetched + * @param recCount number of users to be fetched from the first one * @return a JsonArray of Keycloak UserRepresentations. */ public Uni> listAllUsers(final String realm, final String token, - final String keycloakClientId, Integer maxUsers) { - int bufferSize = 100, cursor = 0; - LOGGER.info("#listAllUsers()..."); - return this.listAllUsersRec(realm, token, keycloakClientId, cursor, bufferSize, - new ArrayList<>(), maxUsers); + final String keycloakClientId, Integer first, Integer recCount) { + + return this.listAllUsersRec(realm, token, keycloakClientId, first, recCount, + new ArrayList<>()); } private Uni> listAllUsersRec(final String realm, final String token, - final String keycloakClientId, int cursor, int bufferSize, - List res, Integer maxUsers) { - LOGGER.info("#listAllUsersRec(cursor,bufferSize,usersFetched)...{}-{}-{}", cursor, bufferSize, - res.size()); - return keycloakClient.listAllUsers(BEARER + token, realm, GRANT_TYPE, keycloakClientId, cursor, - bufferSize) + final String keycloakClientId, Integer first, Integer recCount, + List res) { + LOGGER.debug("#listAllUsersRec(first, usersFetched)...{}-{}", first, res.size()); + return keycloakClient.listAllUsers(BEARER + token, realm, GRANT_TYPE, keycloakClientId, first, + (KC_BUFFER_SIZE < (recCount - first) ? KC_BUFFER_SIZE : recCount - first)) .map(KeycloakUserRepresentation::allFrom) - .flatMap(hundredUsers -> { - res.addAll(hundredUsers); - if (hundredUsers.size() < bufferSize || hundredUsers.size() >= maxUsers) { + .flatMap(currentSelection -> { + res.addAll(currentSelection); + if (currentSelection.size() < KC_BUFFER_SIZE || res.size() >= recCount) { return Uni.createFrom().item(res); // Recursion Base case } else { - return this.listAllUsersRec(realm, token, keycloakClientId, cursor + bufferSize, - bufferSize, res, maxUsers); + return this.listAllUsersRec(realm, token, keycloakClientId, first + KC_BUFFER_SIZE, + recCount, + res); } }); } @@ -316,6 +318,22 @@ public Uni> listAllGroups(final String realm, final St .map(GroupRepresentation::allFrom); } + /** + * Creates a group in Keycloak + * + * @param realm the realm name in which the users are going to be queried. + * @param token access token provided by the keycloak SecurityIdentity. + * @param keycloakClientId id of the client (service name). + * @param newGroup group that is going to be created into the Keycloak database. + * @return a GroupRepresentation of the new group. + */ + public Uni createGroup(final String realm, final String token, + final String keycloakClientId, final GroupRepresentation newGroup) { + return keycloakClient.createGroup(BEARER + token, realm, GRANT_TYPE, keycloakClientId, + "{\"name\": \"" + newGroup.name + "\"}") + .replaceWith(this.getGroupInfoNoEnrich(realm, token, keycloakClientId, newGroup.name)); + } + /** * Return information of one group. And enrich it with its members. It can throw * NoSuchGroupException. @@ -332,7 +350,7 @@ public Uni getGroupInfo(final String realm, final String to return getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) .flatMap(group -> this.getGroupRolesById(realm, token, keycloakClientId, group.id) .map(group::addRoles)) - .flatMap(group -> this.getUsersForGroupById(realm, token, keycloakClientId, group.id) + .flatMap(group -> this.getGroupMembers(realm, token, keycloakClientId, group.name) .map(group::addMembers) ); } @@ -346,6 +364,66 @@ public Uni getGroupInfoNoEnrich(final String realm, final S .map(GroupRepresentation::from); } + /** + * Deletes a group in Keycloak + * + * @param realm the realm name in which the users are going to be queried. + * @param token access token provided by the keycloak SecurityIdentity. + * @param keycloakClientId id of the client (service name). + * @param groupName name of the group that is desired to be deleted. + * @return True if the groups has been removed from the DB, FALSE otherwise. + */ + public Uni deleteGroup(final String realm, final String token, + final String keycloakClientId, final String groupName) { + return this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) + .map(GroupRepresentation::getId) + .flatMap(groupId -> keycloakClient.deleteGroup(BEARER + token, realm, GRANT_TYPE, + keycloakClientId, groupId)) + .replaceWith(this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) + .map(x -> Boolean.FALSE) + .onFailure(NoSuchGroupException.class).recoverWithNull().replaceWith(Boolean.TRUE)); + + } + + /** + * Add the given roles to the given group in Keycloak. + * + * @param realm the realm name in which the users are going to be queried. + * @param token access token provided by the keycloak SecurityIdentity. + * @param keycloakClientId id of the client (service name). + * @param groupName name of the group that is desired to be updated. + * @param roles an array of the roles that are going to be added to the group. + * @return True if the groups has been removed from the DB, FALSE otherwise. + */ + public Uni addRolesToGroup(final String realm, final String token, + final String keycloakClientId, final String groupName, RoleRepresentation[] roles) { + + return this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) + .map(GroupRepresentation::getId) + .flatMap(groupId -> keycloakClient.addRolesToGroup(BEARER + token, realm, GRANT_TYPE, + keycloakClientId, groupId, roles)) + .replaceWith(this.getGroupInfo(realm, token, keycloakClientId, groupName)); + } + + /** + * Removes the given roles from the given group in Keycloak. + * + * @param realm the realm name in which the users are going to be queried. + * @param token access token provided by the keycloak SecurityIdentity. + * @param keycloakClientId id of the client (service name). + * @param groupName name of the group that is desired to be updated. + * @param roles an array of the roles that are going to be removed from the group. + * @return True if the groups has been removed from the DB, FALSE otherwise. + */ + public Uni removeRolesFromGroup(final String realm, final String token, + final String keycloakClientId, final String groupName, RoleRepresentation[] roles) { + return this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) + .map(GroupRepresentation::getId) + .flatMap(groupId -> keycloakClient.removeRolesFromGroup(BEARER + token, realm, GRANT_TYPE, + keycloakClientId, groupId, roles)) + .replaceWith(this.getGroupInfo(realm, token, keycloakClientId, groupName)); + } + /** * Gets all the users that belongs to a concrete group. It can throw NoSuchGroupException. * @@ -353,22 +431,55 @@ public Uni getGroupInfoNoEnrich(final String realm, final S * @param token access token provided by the keycloak SecurityIdentity. * @param keycloakClientId id of the client (service name). * @param groupName name of the group that is going to be queried. - * @return a JsonArray of UserRepresentation. + * @return a JsonArray of GroupRepresentation. */ - public Uni> getUsersForGroup(final String realm, + public Uni> getGroupMembers(final String realm, final String token, final String keycloakClientId, final String groupName) { return this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) .map(GroupRepresentation::getId) - .flatMap(userId -> keycloakClient.getGroupUsers(BEARER + token, realm, GRANT_TYPE, - keycloakClientId, userId)) - .map(KeycloakUserRepresentation::allFrom); + .flatMap(groupId -> this.getGroupMembersRec(realm, token, keycloakClientId, groupId, 0, + Integer.MAX_VALUE, new ArrayList<>())); + } - private Uni> getUsersForGroupById(final String realm, - final String token, final String keycloakClientId, final String id) { - return keycloakClient.getGroupUsers(BEARER + token, realm, GRANT_TYPE, - keycloakClientId, id) - .map(KeycloakUserRepresentation::allFrom); + /** + * Gets all the users that belongs to a concrete group. It can throw NoSuchGroupException. + * + * @param realm the realm name in which the users are going to be queried. + * @param token access token provided by the keycloak SecurityIdentity. + * @param keycloakClientId id of the client (service name). + * @param groupName name of the group that is going to be queried. + * @param first first user to be fetched within the members of the group + * @param recCount number of users to be fetched from the first one + * @return a JsonArray of GroupRepresentation. + */ + public Uni> getGroupMembers(final String realm, + final String token, final String keycloakClientId, final String groupName, Integer first, + Integer recCount) { + return this.getGroupInfoNoEnrich(realm, token, keycloakClientId, groupName) + .map(GroupRepresentation::getId) + .flatMap(groupId -> this.getGroupMembersRec(realm, token, keycloakClientId, groupId, first, + recCount, new ArrayList<>())); + + } + + private Uni> getGroupMembersRec(final String realm, + final String token, + final String keycloakClientId, final String groupId, Integer first, Integer recCount, + List res) { + LOGGER.debug("#getGroupMembersRec(cursor, usersFetched)...{}-{}", first, res.size()); + return keycloakClient.getGroupUsers(BEARER + token, realm, GRANT_TYPE, keycloakClientId, + groupId, first, (KC_BUFFER_SIZE < (recCount - first) ? KC_BUFFER_SIZE : recCount - first)) + .map(KeycloakUserRepresentation::allFrom) + .flatMap(currentSelection -> { + res.addAll(currentSelection); + if (currentSelection.size() < KC_BUFFER_SIZE || res.size() >= recCount) { + return Uni.createFrom().item(res); // Recursion Base case + } else { + return this.getGroupMembersRec(realm, token, keycloakClientId, groupId, + first + KC_BUFFER_SIZE, recCount, res); + } + }); } /** @@ -423,6 +534,8 @@ public Uni deleteUserFromGroup(final String realm, f } /******************************* ROLE FUNCTIONS *******************************/ + + /** * Return a List of RoleRepresentation with all the roles to the User. * @@ -548,7 +661,7 @@ public Uni> getAllUserInEffectiveRole(final Stri .combinedWith((users, groups) -> { Builder> builder = Uni.join().builder(); for (GroupRepresentation group : groups) { - builder.add(this.getUsersForGroup(realm, token, keycloakClientId, group.name)); + builder.add(this.getGroupMembers(realm, token, keycloakClientId, group.name)); } return builder.joinAll().andCollectFailures() .map(listOfList -> listOfList.stream() diff --git a/src/main/java/com/trikorasolutions/keycloak/client/clientresource/KeycloakAuthAdminResource.java b/src/main/java/com/trikorasolutions/keycloak/client/clientresource/KeycloakAuthAdminResource.java index 6579797..4612a20 100644 --- a/src/main/java/com/trikorasolutions/keycloak/client/clientresource/KeycloakAuthAdminResource.java +++ b/src/main/java/com/trikorasolutions/keycloak/client/clientresource/KeycloakAuthAdminResource.java @@ -1,12 +1,23 @@ package com.trikorasolutions.keycloak.client.clientresource; +import com.trikorasolutions.keycloak.client.dto.GroupRepresentation; +import com.trikorasolutions.keycloak.client.dto.RoleRepresentation; import com.trikorasolutions.keycloak.client.dto.UserRepresentation; import com.trikorasolutions.keycloak.client.dto.UserRepresentation.UserDtoCredential; import io.smallrye.mutiny.Uni; -import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import javax.json.JsonArray; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; /** * Common arguments to all the methods: @@ -55,7 +66,8 @@ Uni updateUser(@HeaderParam("Authorization") String bearerToken, * Updated a user password in Keycloak. * * @param id Id of the user that is going to be updated. - * @param body Raw string containing the new user password in the CredentialRepresentation format. + * @param body Raw string containing the new user password in the CredentialRepresentation + * format. * @return -. */ @PUT @@ -121,6 +133,20 @@ Uni listAllGroups(@HeaderParam("Authorization") String bearerToken, @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, @QueryParam("client_id") String clientId); + /** + * This will update the group and set the parent if it exists. Create it and set the parent if the + * group doesn't exist. + * + * @param group that is going to be created in the Keycloak database. + * @return a GroupRepresentation of the new group. + */ + @POST + @Path("/realms/{realm}/groups") + @Produces(MediaType.APPLICATION_JSON) + Uni createGroup(@HeaderParam("Authorization") String bearerToken, + @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, + @QueryParam("client_id") String clientId, String group); + /** * Return information of one group. * @@ -134,6 +160,20 @@ Uni getGroupInfo(@HeaderParam("Authorization") String bearerToken, @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, @QueryParam("client_id") String clientId, @QueryParam("search") String groupName); + + /** + * This method deletes a group. + * + * @param id that is going to be deleted from the Keycloak database. + * @return - + */ + @DELETE + @Path("/realms/{realm}/groups/{id}") + @Produces(MediaType.APPLICATION_JSON) + Uni deleteGroup(@HeaderParam("Authorization") String bearerToken, + @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, + @QueryParam("client_id") String clientId, @PathParam("id") String id); + /** * Gets all the users that belongs to a concrete group. * @@ -145,7 +185,8 @@ Uni getGroupInfo(@HeaderParam("Authorization") String bearerToken, @Produces(MediaType.APPLICATION_JSON) Uni getGroupUsers(@HeaderParam("Authorization") String bearerToken, @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, - @QueryParam("client_id") String clientId, @PathParam("id") String id); + @QueryParam("client_id") String clientId, @PathParam("id") String id, + @QueryParam("first") Integer first, @QueryParam("max") Integer max); /** * Return all the groups of a given user. @@ -229,6 +270,38 @@ Uni getUserRoles(@HeaderParam("Authorization") String bearerToken, @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, @QueryParam("client_id") String clientId, @PathParam("id") String userId); + /** + * Add the given role mappings to a group + * + * @param groupId id of the group to be upgraded. + * @param roles array containing the roles to be added, both id and name of the roles need to be + * provided. + * @return JsonArray with the roles + */ + @POST + @Path("/realms/{realm}/groups/{id}/role-mappings/realm") + @Produces(MediaType.APPLICATION_JSON) + Uni addRolesToGroup(@HeaderParam("Authorization") String bearerToken, + @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, + @QueryParam("client_id") String clientId, @PathParam("id") String groupId, + RoleRepresentation[] roles); + + /** + * Remove the given role mappings from a group + * + * @param groupId id of the group to be upgraded. + * @param roles array containing the roles to be added, both id and name of the roles need to be + * provided. + * @return JsonArray with the roles + */ + @DELETE + @Path("/realms/{realm}/groups/{id}/role-mappings/realm") + @Produces(MediaType.APPLICATION_JSON) + Uni removeRolesFromGroup(@HeaderParam("Authorization") String bearerToken, + @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, + @QueryParam("client_id") String clientId, @PathParam("id") String groupId, + RoleRepresentation[] roles); + /** * Return ALL the roles of one group * @@ -241,4 +314,6 @@ Uni getUserRoles(@HeaderParam("Authorization") String bearerToken, Uni getGroupRoles(@HeaderParam("Authorization") String bearerToken, @PathParam("realm") String realm, @QueryParam("grant_type") String grantType, @QueryParam("client_id") String clientId, @PathParam("id") String groupId); + + } diff --git a/src/main/java/com/trikorasolutions/keycloak/client/dto/GroupRepresentation.java b/src/main/java/com/trikorasolutions/keycloak/client/dto/GroupRepresentation.java index c181243..39814a6 100644 --- a/src/main/java/com/trikorasolutions/keycloak/client/dto/GroupRepresentation.java +++ b/src/main/java/com/trikorasolutions/keycloak/client/dto/GroupRepresentation.java @@ -29,12 +29,17 @@ public class GroupRepresentation { @JsonProperty("members") public Set members; - public GroupRepresentation(String id) { + public GroupRepresentation(String id, String name) { this.id = id; + this.name = name; this.roles = new LinkedHashSet<>(); this.members = new LinkedHashSet<>(); } + public GroupRepresentation(String name) { + this.name = name; + } + public GroupRepresentation(String id, String name, String path) { this.id = id; this.name = name; @@ -52,16 +57,11 @@ public static GroupRepresentation from(JsonObject from) { // Create the DTO only with the mandatory fields GroupRepresentation parsedResponse = new GroupRepresentation( - from.getString("id")); + from.getString("id"), from.getString("name")); - // Then add only the available optional fields - Iterator iterator = from.keySet().iterator(); - while (iterator.hasNext()) { - String key = iterator.next(); + // Then add only the available optional fields (more fields will be added in future releases) + for (String key : from.keySet()) { switch (key) { - case "name": - parsedResponse.setName(from.getString(key)); - break; case "path": parsedResponse.setPath(from.getString(key)); break; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0e76212..a14859c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -11,7 +11,8 @@ quarkus.http.cors=true quarkus.keycloak.policy-enforcer.enable=true quarkus.keycloak.policy-enforcer.lazy-load-paths=false -trikora.realm-name=trikorasolutions +trikora.keycloak.realm-name=trikorasolutions +trikora.keycloak.buffer-size=100 # REST CLIENT #keycloak-api/mp-rest/url=https://localhost:8543/ @@ -27,6 +28,9 @@ keycloak-api/mp-rest/scope=javax.inject.Singleton # LOG # ####### -%test.quarkus.log.level=INFO +quarkus.log.level=WARN + %dev.quarkus.log.level=INFO -%test.quarkus.log.category."org.jboss.resteasy".level=INFO \ No newline at end of file + +%test.quarkus.log.level=INFO +%test.quarkus.log.category."org.jboss.resteasy".level=INFO diff --git a/src/test/java/com/trikorasolutions/keycloak/client/LogicCRUDTest.java b/src/test/java/com/trikorasolutions/keycloak/client/LogicCRUDTest.java index 169524f..8454e9c 100644 --- a/src/test/java/com/trikorasolutions/keycloak/client/LogicCRUDTest.java +++ b/src/test/java/com/trikorasolutions/keycloak/client/LogicCRUDTest.java @@ -311,9 +311,26 @@ public void testListKeycloakUsers() { List usernameList = logicResponse.stream() .map(tuple -> tuple.username).collect(Collectors.toList()); - assertThat(usernameList, hasItems("jdoe", ADM, "mrsquare", "mrtriangle")); - LOGGER.info("TOTAL USERS IN REALM LIST: {}", logicResponse.size()); + LOGGER.info("TOTAL USERS IN REALM LIST: {}{}", logicResponse.size(), logicResponse.get(1)); + + // Test base case of recursion + int f = 50, m = 75; + logicResponse = keycloakClientLogic.listAllUsers( + tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), f, m) + .await().indefinitely(); + assertThat(logicResponse.size(), is(m - f)); + m = 275; + logicResponse = keycloakClientLogic.listAllUsers( + tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), f, m) + .await().indefinitely(); + assertThat(logicResponse.size(), is(m - f)); + f = 0; + m = 300; + logicResponse = keycloakClientLogic.listAllUsers( + tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), f, m) + .await().indefinitely(); + assertThat(logicResponse.size(), is(m - f)); } @Test diff --git a/src/test/java/com/trikorasolutions/keycloak/client/LogicGroupTest.java b/src/test/java/com/trikorasolutions/keycloak/client/LogicGroupTest.java index 7c3919e..407e621 100644 --- a/src/test/java/com/trikorasolutions/keycloak/client/LogicGroupTest.java +++ b/src/test/java/com/trikorasolutions/keycloak/client/LogicGroupTest.java @@ -10,17 +10,17 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; - import java.util.List; import java.util.stream.Collectors; import static com.trikorasolutions.keycloak.client.TrikoraKeycloakClientInfo.ADM; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; @QuarkusTest public class LogicGroupTest { + private static final Logger LOGGER = LoggerFactory.getLogger(LogicGroupTest.class); @Inject @@ -29,16 +29,36 @@ public class LogicGroupTest { @Inject TrikoraKeycloakClientInfo tkrKcCli; + + @Test + public void testCreateGroupOk() { + String accessToken = tkrKcCli.getAccessToken(ADM); + GroupRepresentation newGroup = new GroupRepresentation("TEST_CREATE"); + LOGGER.info("test{}", newGroup); + GroupRepresentation logicResponse; + boolean logicResponse2; + + logicResponse = keycloakClientLogic.createGroup(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), newGroup).await().indefinitely(); + assertThat(logicResponse.getName(), is(newGroup.name)); + + logicResponse2= keycloakClientLogic.deleteGroup(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), logicResponse.name).await().indefinitely(); + assertThat(logicResponse2, is(true)); + + } + @Test public void testGroupInfoOk() { String accessToken = tkrKcCli.getAccessToken(ADM); GroupRepresentation logicResponse; - logicResponse = keycloakClientLogic.getGroupInfo(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "TENANT_TEST").await().indefinitely(); + logicResponse = keycloakClientLogic.getGroupInfo(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), + "TENANT_TEST").await().indefinitely(); assertThat(logicResponse.getName(), is("TENANT_TEST")); - LOGGER.info("test{}",logicResponse); + LOGGER.info("test{}", logicResponse); } @Test @@ -47,11 +67,10 @@ public void testGroupInfoErr() { try { keycloakClientLogic.getGroupInfo(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "unknown").onFailure(NoSuchGroupException.class).transform(x -> { + "unknown").onFailure(NoSuchGroupException.class).transform(x -> { throw (NoSuchGroupException) x; }).await().indefinitely(); - - assertTrue(false); + fail(); } catch (NoSuchGroupException ex) { assertThat(ex.getClass(), is(NoSuchGroupException.class)); assertThat(ex.getMessage(), containsString("unknown")); @@ -63,12 +82,12 @@ public void testGroupListUsers() { String accessToken = tkrKcCli.getAccessToken(ADM); List logicResponse; - logicResponse = keycloakClientLogic.getUsersForGroup(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "TENANT_TEST").await().indefinitely(); + logicResponse = keycloakClientLogic.getGroupMembers(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), "TENANT_TEST").await().indefinitely(); List userRepresentation = logicResponse.stream() - .map(user -> user.username) - .collect(Collectors.toList()); + .map(user -> user.username) + .collect(Collectors.toList()); assertThat(userRepresentation.size(), greaterThanOrEqualTo(1)); assertThat(userRepresentation, hasItem(ADM)); } @@ -80,8 +99,9 @@ public void testPutAndRemoveUserInGroup() { List logicResponse2; // Put a new user in the group - logicResponse = keycloakClientLogic.putUserInGroup(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "mrsquare", "TENANT_TEST").await().indefinitely(); + logicResponse = keycloakClientLogic.putUserInGroup(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), + "mrsquare", "TENANT_TEST").await().indefinitely(); assertThat(logicResponse.username, is("mrsquare")); assertThat(logicResponse.groups.stream() @@ -89,25 +109,26 @@ public void testPutAndRemoveUserInGroup() { .collect(Collectors.toList()), hasItem("TENANT_TEST")); // Check if the change has been persisted in keycloak - logicResponse2 = keycloakClientLogic.getUsersForGroup(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "TENANT_TEST").await().indefinitely(); + logicResponse2 = keycloakClientLogic.getGroupMembers(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), "TENANT_TEST").await().indefinitely(); List userRepresentation = logicResponse2.stream() - .map(user -> user.username) - .collect(Collectors.toList()); + .map(user -> user.username) + .collect(Collectors.toList()); assertThat(userRepresentation.size(), greaterThanOrEqualTo(1)); assertThat(userRepresentation, hasItem("mrsquare")); // Kick the user out of the group - logicResponse = keycloakClientLogic.deleteUserFromGroup(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "mrsquare", "TENANT_TEST").await().indefinitely(); + logicResponse = keycloakClientLogic.deleteUserFromGroup(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), + "mrsquare", "TENANT_TEST").await().indefinitely(); assertThat(logicResponse.username, is("mrsquare")); // Check if the change has been persisted in keycloak - logicResponse2 = keycloakClientLogic.getUsersForGroup(tkrKcCli.getRealmName(), accessToken, tkrKcCli.getClientId(), - "TENANT_TEST").await().indefinitely(); + logicResponse2 = keycloakClientLogic.getGroupMembers(tkrKcCli.getRealmName(), accessToken, + tkrKcCli.getClientId(), "TENANT_TEST").await().indefinitely(); userRepresentation = logicResponse2.stream() - .map(user -> user.username) - .collect(Collectors.toList()); + .map(user -> user.username) + .collect(Collectors.toList()); assertThat(userRepresentation.size(), greaterThanOrEqualTo(0)); assertThat(userRepresentation, not(hasItem("mrsquare"))); } diff --git a/src/test/java/com/trikorasolutions/keycloak/client/TrikoraKeycloakClientInfo.java b/src/test/java/com/trikorasolutions/keycloak/client/TrikoraKeycloakClientInfo.java index fc2bd18..8ff4408 100644 --- a/src/test/java/com/trikorasolutions/keycloak/client/TrikoraKeycloakClientInfo.java +++ b/src/test/java/com/trikorasolutions/keycloak/client/TrikoraKeycloakClientInfo.java @@ -31,7 +31,7 @@ public class TrikoraKeycloakClientInfo { @ConfigProperty(name = "quarkus.oidc.auth-server-url") protected String clientServerUrl; - @ConfigProperty(name = "trikora.realm-name") + @ConfigProperty(name = "trikora.keycloak.realm-name") protected String realmName; public String getAccessToken(String userName) {