Search code examples
javarestpostmankeycloak

Keycloak. Could not find client when trying to create a client-level role


Initially, I couldn't create a client-level role using keycloak-admin-client. I decided to try to do this via the API using Postman in order to make sure that it doesn't work out that way either.

I think I'm sending the request correctly. The authorization token in the headers and the json representation of the role in the body. enter image description here enter image description here

I claim that the client exists, the user I use has administrator rights.

In my java project, it looks like this:

    public int createClient(String clientId) {
        ClientRepresentation clientRepresentation = new ClientRepresentation();
        clientRepresentation.setClientId(clientId);
        clientRepresentation.setPublicClient(false);
        clientRepresentation.setEnabled(true);
        clientRepresentation.setServiceAccountsEnabled(true);

        Response response = clientsManager.create(clientRepresentation);
        int statusCode = response.getStatus();
        log.info("HTTP Status of client creation = {}", statusCode);

        if (statusCode == 201) fillClientWithRoles(clientId);
        return statusCode;
    }

    public void fillClientWithRoles(String clientId) {
        ClientResource clientResource = clientsManager.get(clientId);
        log.info("client: {}", clientResource);
        for (ClientRole role : ClientRole.values()) {
            RoleRepresentation roleRepresentation = new RoleRepresentation();
            roleRepresentation.setName(role.name());
            roleRepresentation.setClientRole(true);
            roleRepresentation.setComposite(false);

            clientResource.roles().create(roleRepresentation);
        }
    }

The Keycloak object is configured correctly. I can, for example, successfully create new users

I reread a bunch of articles, turned to bots for advice, but I still haven't found a solution that would explain the cause of the 404 error in this request and help solve the problem

2024-05-28T14:53:08.288+03:00 ERROR 14920 --- [portal-ms] [io-60005-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: jakarta.ws.rs.NotFoundException: HTTP 404 Not Found] with root cause

jakarta.ws.rs.NotFoundException: HTTP 404 Not Found
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:242) ~[resteasy-client-6.2.9.Final.jar:6.2.9.Final]
    at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.DefaultEntityExtractorFactory$3.extractEntity(DefaultEntityExtractorFactory.java:41) ~[resteasy-client-6.2.9.Final.jar:6.2.9.Final]
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:136) ~[resteasy-client-6.2.9.Final.jar:6.2.9.Final]
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:103) ~[resteasy-client-6.2.9.Final.jar:6.2.9.Final]
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:102) ~[resteasy-client-6.2.9.Final.jar:6.2.9.Final]
    at jdk.proxy2/jdk.proxy2.$Proxy192.create(Unknown Source) ~[na:na]
    at ru.gnivc.portalservice.service.KeycloakService.fillClientWithRoles(KeycloakService.java:124) ~[classes/:na]
    at ru.gnivc.portalservice.service.KeycloakService.createClient(KeycloakService.java:109) ~[classes/:na]
    at ru.gnivc.portalservice.service.CompanyService.createCompany(CompanyService.java:27) ~[classes/:na]
    at ru.gnivc.portalservice.controller.CompanyController.createCompany(CompanyController.java:22) ~[classes/:na

Solution

  • The problem was that when contacting the client, we have to use the UUID assigned to him when creating (automatically). This is not at all obvious, because in the Keyclock UI it is not even displayed to customers. Below I will give an example of creating a client with assigning client roles to it.

    I hope that it will help anyone who is faced with the same problem in the future!!!

    
    //ClientsResource clientsManager = clientsManager = realm.clients(); - it is used further
        public int createClient(String clientId) {
            ClientRepresentation clientRepresentation = new ClientRepresentation();
            clientRepresentation.setClientId(clientId);
            clientRepresentation.setPublicClient(false);
            clientRepresentation.setEnabled(true);
            clientRepresentation.setServiceAccountsEnabled(true);
    
            Response response = clientsManager.create(clientRepresentation);
            int statusCode = response.getStatus();
    
            if (statusCode == 201) {
                String createdId = CreatedResponseUtil.getCreatedId(response); //here we can get client's assigned UUID
                fillClientWithRoles(createdId);
            }
            return statusCode;
        }
    
        public void fillClientWithRoles(String clientId) {
            ClientResource clientResource = clientsManager.get(clientId); //here we muse use UUID of the client
            for (ClientRole role : ClientRole.values()) {
                RoleRepresentation roleRepresentation = new RoleRepresentation();
                roleRepresentation.setName(role.name());
                roleRepresentation.setClientRole(true);
                roleRepresentation.setComposite(false);
    
                clientResource.roles().create(roleRepresentation);
            }
        }