From d93ce34d6685cd641df1d76578a701917915622f Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 24 Oct 2024 11:04:49 +0200 Subject: [PATCH] Admin-client compatibility with the future Keycloak server versions closes #94 Signed-off-by: mposolda Co-authored-by: Jon Koops Signed-off-by: Marek Posolda --- README.md | 6 +++- .../admin/client/JacksonProvider.java | 6 +++- .../java/org/keycloak/common/Profile.java | 6 +--- .../PropertiesFileProfileConfigResolver.java | 32 ------------------- .../testsuite/util/AdminClientUtil.java | 30 +++++------------ 5 files changed, 19 insertions(+), 61 deletions(-) delete mode 100644 client-common-synced/src/main/java/org/keycloak/common/profile/PropertiesFileProfileConfigResolver.java diff --git a/README.md b/README.md index a2e1fdb..4a53111 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,11 @@ and hence are supposed to be updated there (whenever needed) and synced into thi ## Syncing the files from Keycloak repository -* Checkout [main Keycloak server repository](https://github.com/keycloak/keycloak) and build it on your laptop to make sure latest Keycloak stuff available in your local maven repository. +* Fetch [main Keycloak server repository](https://github.com/keycloak/keycloak) and checkout the last `release/X.Y` branch (For example `git checkout release/26.0`). Note that we usually cannot +sync from the server `main` branch as it is under development and there is still a chance that some things being developed here would be later updated/removed. Which could be an issue as for client, we +want to preserve backwards compatibility. + +* build it on your laptop to make sure latest Keycloak stuff available in your local maven repository. * Run [sync-keycloak-sources.sh](.github/scripts/sync-keycloak-sources.sh) diff --git a/admin-client/src/main/java/org/keycloak/admin/client/JacksonProvider.java b/admin-client/src/main/java/org/keycloak/admin/client/JacksonProvider.java index bccb178..ecd5773 100644 --- a/admin-client/src/main/java/org/keycloak/admin/client/JacksonProvider.java +++ b/admin-client/src/main/java/org/keycloak/admin/client/JacksonProvider.java @@ -1,5 +1,6 @@ package org.keycloak.admin.client; +import com.fasterxml.jackson.databind.DeserializationFeature; import jakarta.ws.rs.core.MediaType; import com.fasterxml.jackson.annotation.JsonInclude; @@ -14,7 +15,10 @@ public ObjectMapper locateMapper(Class type, MediaType mediaType) { // Same like JSONSerialization class. Makes it possible to use admin-client against older versions of Keycloak server where the properties on representations might be different objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - + + // The client must work with the newer versions of Keycloak server, which might contain the JSON fields not yet known by the client. So unknown fields will be ignored. + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return objectMapper; } } diff --git a/client-common-synced/src/main/java/org/keycloak/common/Profile.java b/client-common-synced/src/main/java/org/keycloak/common/Profile.java index a4c9095..b355154 100755 --- a/client-common-synced/src/main/java/org/keycloak/common/Profile.java +++ b/client-common-synced/src/main/java/org/keycloak/common/Profile.java @@ -140,9 +140,6 @@ public enum Feature { this(label, type, version, null, dependencies); } - /** - * allowNameKey should be false for new versioned features to disallow using a legacy name, like account2 - */ Feature(String label, Type type, int version, BooleanSupplier isAvailable, Feature... dependencies) { this.label = label; this.type = type; @@ -161,8 +158,7 @@ public enum Feature { } /** - * Get the key that uniquely identifies this feature, may be used by users if - * allowNameKey is true. + * Get the key that uniquely identifies this feature *

* {@link #getVersionedKey()} should instead be shown to users where possible. */ diff --git a/client-common-synced/src/main/java/org/keycloak/common/profile/PropertiesFileProfileConfigResolver.java b/client-common-synced/src/main/java/org/keycloak/common/profile/PropertiesFileProfileConfigResolver.java deleted file mode 100644 index 012d80e..0000000 --- a/client-common-synced/src/main/java/org/keycloak/common/profile/PropertiesFileProfileConfigResolver.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.keycloak.common.profile; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -public class PropertiesFileProfileConfigResolver extends PropertiesProfileConfigResolver { - - public PropertiesFileProfileConfigResolver() { - super(loadProperties()); - } - - private static Properties loadProperties() { - Properties properties = new Properties(); - try { - String jbossServerConfigDir = System.getProperty("jboss.server.config.dir"); - if (jbossServerConfigDir != null) { - File file = new File(jbossServerConfigDir, "profile.properties"); - if (file.isFile()) { - try (FileInputStream is = new FileInputStream(file)) { - properties.load(is); - } - } - } - } catch (IOException e) { - throw new ProfileException("Failed to load profile properties file", e); - } - return properties; - } - -} diff --git a/testsuite/framework/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java b/testsuite/framework/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java index fd0905b..0b4ca99 100644 --- a/testsuite/framework/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java +++ b/testsuite/framework/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java @@ -29,6 +29,7 @@ import org.jboss.resteasy.client.jaxrs.engines.ClientHttpEngineBuilder43; import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.JacksonProvider; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.KeycloakBuilder; import org.keycloak.client.testsuite.models.Constants; @@ -70,8 +71,8 @@ public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String public static Keycloak createAdminClientWithClientCredentials(String realmName, String clientId, String clientSecret, String scope) { - boolean ignoreUnknownProperties = false; - ResteasyClient resteasyClient = createResteasyClient(ignoreUnknownProperties, null); + boolean ignoreUnknownProperties = true; + ResteasyClient resteasyClient = createResteasyClient(null); return KeycloakBuilder.builder() .serverUrl(getAuthServerContextRoot()) @@ -91,29 +92,14 @@ public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws return createAdminClient(ignoreUnknownProperties, getAuthServerContextRoot()); } - public static ResteasyClient createResteasyClient() { - try { - return createResteasyClient(false, null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static ResteasyClient createResteasyClient(boolean ignoreUnknownProperties, Boolean followRedirects) { + public static ResteasyClient createResteasyClient(Boolean followRedirects) { ResteasyClientBuilder resteasyClientBuilder = (ResteasyClientBuilder) ResteasyClientBuilder.newBuilder(); resteasyClientBuilder.sslContext(buildSslContext()); - // We need to ignore unknown JSON properties e.g. in the adapter configuration representation - // during adapter backward compatibility testing - if (ignoreUnknownProperties) { - // We need to use anonymous class to avoid the following error from RESTEasy: - // Provider class org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider is already registered. 2nd registration is being ignored. - ResteasyJackson2Provider jacksonProvider = new ResteasyJackson2Provider() {}; - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - jacksonProvider.setMapper(objectMapper); - resteasyClientBuilder.register(jacksonProvider, 100); - } + // We need to use subclass (or anonymous class) to avoid the following error from RESTEasy: + // Provider class org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider is already registered. 2nd registration is being ignored. + ResteasyJackson2Provider jacksonProvider = new JacksonProvider(); + resteasyClientBuilder.register(jacksonProvider, 100); resteasyClientBuilder .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD)