michealAtmi
michealAtmi

Reputation: 1042

Keycloak user resource - return user representation with roles and groups instead querying rest api for roles and groups

I have to search users by text, groups and roles and it takes 6 seconds to query for users, groups and roles for each user, it is about 15 HTTP requests to Keycloak REST API.

Such slow searching is not acceptable from GUI point of view.. How u search users in your projects with Keycloak ? Do you synchronize users from Keycloak? Then data would not be fresh.. or maybe it is possible to write someadapter in Keycloak to synchronize data to my application, so the changes would be reflected immediatelly in my database and I would search users in my database. .? Or maybe uconnect to Keycloak data database ? But then u limit yourself to Keycloak version..

When serching users you get UserResources and u can do userResource.toRepresentation() to get specific data an you see groups and roles collections that are always empty. Is it possible to retrieve UserResources that have groups and roles filled? Currently userResource.toRepresentation() returns user but with null groups and roles. So what groups and roles collections are for in UserRepresentation if they are always null?

Upvotes: 1

Views: 3768

Answers (2)

Kevin O.
Kevin O.

Reputation: 444

How to get all users of a certain client by a certain role like all 'admins'?

Note that for client roles you must use the client's internal ID, not the name of the client!

package com.audija.admin.service.security;

import com.audija.admin.controller.EmailsController;
import com.audija.admin.security.KeycloakConfig;
import com.audija.admin.util.Role;
import org.keycloak.admin.client.resource.*;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Service
public class KeycloakService {

    private static final Logger logger = Logger.getLogger(EmailsController.class.getName());

    private final String publicClientId;

    public KeycloakService(@Value("${keycloak.resource}") String publicClientId) {
        this.publicClientId = publicClientId;
    }

    private RealmResource getRealmResource() {
        return KeycloakConfig.GLOBAL_KEYCLOAK_INSTANCE.realm(KeycloakConfig.REALM);
    }

    @Transactional
    public List < UserRepresentation > getAdmins() {

        List < UserRepresentation > admins = new ArrayList < > ();
        logger.info("Start fetching admins ...");

        long totalStartTime = System.currentTimeMillis();

        try {
            admins = fetchUsers();

        } catch (Exception exc) {

            logger.info(String.format("\r✗ Failed to fetch admins: %s", exc.getMessage()));

            throw new RuntimeException("Failed to fetch admins", exc);

        } finally {

            long totalEndTime = System.currentTimeMillis();

            logger.info(String.format("✓ Fetched %d admins", admins.size()));
            logger.info(String.format("Total fetch time: %.2f seconds", (totalEndTime - totalStartTime) / 1000.0));
        }
        return admins;
    }

    private List < UserRepresentation > fetchUsers() {

        RealmResource realmResource = getRealmResource();

        ClientRepresentation client = realmResource.clients().findByClientId(publicClientId).getFirst();

        // Define your role name here.
        RoleResource role = realmResource.clients().get(client.getId()).roles().get(Role.admin.name());

        return role.getUserMembers(0, Integer.MAX_VALUE);
    }
}

Keycloak Version: 22.0.5 Spring Boot Version: 3.3.0

Upvotes: 0

ad2ien
ad2ien

Reputation: 31

It's not exactly the topic but I needed to find the roles associated with a specific user and this question pops first with my keywords web search. Here's what worked for me with keycloak client 13.0.1

RealmResource realmResource = keycloak.realm(REALM);
UsersResource usersResource = realmResource.users();
UserResource userResource =  usersResource.get(USER_ID);
RoleMappingResource roleMappingResource = userResource.roles();
// either realmLevel or clientLevel
RoleScopeResource roleScopeResource = roleMappingResource.realmLevel();
List<RoleRepresentation> rolesRepresentation = roleScopeResource.listAll();

I didn't find it elsewhere, I hope it can be useful.

Upvotes: 3

Related Questions