javakeycloak

Keycloak admin client responds with Bad Request to attempt to list realms


I am attempting a simple test of the health of a fresh instance of Keycloak (running in a Docker container, it so happens), by trying to list the realms using the Java admin client as the admin user. But this repeatedly fails due to an HTTP 400 Bad Request, apparently when the client is attempting to get an access token. How must I configure Keycloak, or the admin client, to do this simple query?

The stack-trace of the failure is thus:

java.lang.AssertionError: Able to list realms
    at [MyClass].listRealms([MyClass].java:69)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    [junit stack-trace]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: javax.ws.rs.ProcessingException: javax.ws.rs.BadRequestException: HTTP 400 Bad Request
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterRequest(ClientInvocation.java:603)
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:440)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:149)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:112)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
    at com.sun.proxy.$Proxy45.findAll(Unknown Source)
    at [MyClass].listRealms([MyClass].java:67)
    ... 67 more
Caused by: javax.ws.rs.BadRequestException: HTTP 400 Bad Request
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:219)
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:195)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:62)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:151)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:112)
    at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
    at com.sun.proxy.$Proxy43.grantToken(Unknown Source)
    at org.keycloak.admin.client.token.TokenManager.grantToken(TokenManager.java:90)
    at org.keycloak.admin.client.token.TokenManager.getAccessToken(TokenManager.java:70)
    at org.keycloak.admin.client.token.TokenManager.getAccessTokenString(TokenManager.java:65)
    at org.keycloak.admin.client.resource.BearerAuthFilter.filter(BearerAuthFilter.java:52)
    at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterRequest(ClientInvocation.java:590)
    ... 73 more

The crucial code doing the query is this:

   public void listRealms() {
      try (var keycloak = container.getKeycloakInstance()) {
         final List<RealmRepresentation> realms;
         try {
            realms = keycloak.realms().findAll();
         } catch (final Exception e) {// provide better diagnostics
            throw new AssertionError("Able to list realms", e);
         }
         assertThat(realms, not(empty()));
      }
   }

with the Keycloak instance created thus:

   private static final String ADMIN_USER = "admin";
   private static final String ADMIN_PASSWORD = "letmein";
   private static final String ADMIN_REALM = "master";
   private static final String ADMIN_CLIENT_ID = null;
...
   public Keycloak getKeycloakInstance() {
      return Keycloak.getInstance(getUri().toASCIIString(), ADMIN_REALM,
               ADMIN_USER, ADMIN_PASSWORD, ADMIN_CLIENT_ID);
   }

That test failure happens to be when running the test in Eclipse. But the problem also occurs when I run the test using Maven (that is, using the maven-failsafe-plugin).

The same failure mode (HTTP 400 Bad Request ) also occurs if I

The URL I am using seems to be correct, because if I deliberately use an incorrect URL path I get the expected HTTP 404 Not Found failure mode, and if I deliberately use an incorrect host name I get the expected UnknownHostException.

This problem occurs with Key cloak version 11.0.2 (the current version at the time of writing) and also occurred with version 11.0.0.


Solution

  • Although Keycloak automatically creates a master realm, with several client IDs, and you can automate setting up an admin user, its seems you can not use those with the Java admin client. You must instead create (or import) a realm and client ID, which you can then indicate when you create the Keycloak instance. Keycloak will not then complain about a Bad Request.