diff --git a/CHANGELOG.md b/CHANGELOG.md index 82e7df8c..0c57ba6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Replace `TotpNotEnabledException` with `UnknownUserTotpIdException`. +## [4.0.2] - 2023-10-19 + +- Fixes serialization of thirdParty config + +## [4.0.1] - 2023-10-19 + +- Fixes cloning of `TenantConfig` object to include `null` values + ## [4.0.0] - 2023-09-19 - Adds support for account linking diff --git a/build.gradle b/build.gradle index 62e73f81..1d323424 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "4.0.0" +version = "4.0.2" repositories { mavenCentral() diff --git a/jar/plugin-interface-4.0.0.jar b/jar/plugin-interface-4.0.2.jar similarity index 70% rename from jar/plugin-interface-4.0.0.jar rename to jar/plugin-interface-4.0.2.jar index 1eedae21..8bd9b976 100644 Binary files a/jar/plugin-interface-4.0.0.jar and b/jar/plugin-interface-4.0.2.jar differ diff --git a/src/main/java/io/supertokens/pluginInterface/multitenancy/TenantConfig.java b/src/main/java/io/supertokens/pluginInterface/multitenancy/TenantConfig.java index 3b490d52..54f331f2 100644 --- a/src/main/java/io/supertokens/pluginInterface/multitenancy/TenantConfig.java +++ b/src/main/java/io/supertokens/pluginInterface/multitenancy/TenantConfig.java @@ -109,6 +109,9 @@ public int hashCode() { public JsonObject toJson(boolean shouldProtectDbConfig, Storage storage, String[] protectedCoreConfigs) { Gson gson = new Gson(); JsonObject tenantConfigObject = gson.toJsonTree(this).getAsJsonObject(); + + tenantConfigObject.add("thirdParty", this.thirdPartyConfig.toJson()); + tenantConfigObject.addProperty("tenantId", this.tenantIdentifier.getTenantId()); if (shouldProtectDbConfig) { diff --git a/src/main/java/io/supertokens/pluginInterface/multitenancy/ThirdPartyConfig.java b/src/main/java/io/supertokens/pluginInterface/multitenancy/ThirdPartyConfig.java index 838f71eb..b4f86418 100644 --- a/src/main/java/io/supertokens/pluginInterface/multitenancy/ThirdPartyConfig.java +++ b/src/main/java/io/supertokens/pluginInterface/multitenancy/ThirdPartyConfig.java @@ -16,8 +16,10 @@ package io.supertokens.pluginInterface.multitenancy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import io.supertokens.pluginInterface.exceptions.InvalidConfigException; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -34,6 +36,50 @@ public ThirdPartyConfig(boolean enabled, @Nullable Provider[] providers) { this.providers = providers == null ? new Provider[0] : providers; } + public JsonObject toJson() { + JsonObject result = new JsonObject(); + result.addProperty("enabled", this.enabled); + result.add("providers", new JsonArray()); + + for (Provider provider : this.providers) { + result.getAsJsonArray("providers").add(provider.toJson()); + } + + return result; + } + + public static boolean unorderedArrayEquals(Object[] array1, Object[] array2) { + if (array1 == null && array2 == null) { + return true; + } else if (array1 == null || array2 == null) { + return false; + } + + List items1 = List.of(array1); + List items2 = new ArrayList<>(); + items2.addAll(Arrays.asList(array2)); + + if (items1.size() != items2.size()) return false; + + for (Object p1 : items1) { + boolean found = false; + for (Object p2 : items2) { + if (p1.equals(p2)) { + found = true; + break; + } + } + + if (!found) { + return false; + } else { + items2.remove(p1); + } + } + + return true; + } + public static class Provider { @Nonnull @@ -102,11 +148,46 @@ public Provider(@Nonnull String thirdPartyId, @Nonnull String name, @Nullable Pr this.userInfoMap = userInfoMap == null ? new UserInfoMap(null, null) : userInfoMap; } + public JsonObject toJson() { + JsonObject result = new Gson().toJsonTree(this).getAsJsonObject(); + + // These properties need to retain null values when serialized + if (this.authorizationEndpointQueryParams != null) { + result.add("authorizationEndpointQueryParams", + new GsonBuilder().serializeNulls().create().toJsonTree(this.authorizationEndpointQueryParams)); + } else { + result.remove("authorizationEndpointQueryParams"); + } + + if (this.tokenEndpointBodyParams != null) { + result.add("tokenEndpointBodyParams", new GsonBuilder().serializeNulls().create().toJsonTree(this.tokenEndpointBodyParams)); + } else { + result.remove("tokenEndpointBodyParams"); + } + + if (this.userInfoEndpointQueryParams != null) { + result.add("userInfoEndpointQueryParams", new GsonBuilder().serializeNulls().create().toJsonTree(this.userInfoEndpointQueryParams)); + } else { + result.remove("userInfoEndpointQueryParams"); + } + + if (this.userInfoEndpointHeaders != null) { + result.add("userInfoEndpointHeaders", new GsonBuilder().serializeNulls().create().toJsonTree(this.userInfoEndpointHeaders)); + } else { + result.remove("userInfoEndpointHeaders"); + } + return result; + } + @Override public boolean equals(Object other) { + if (other == null) { + return false; + } + if (other instanceof Provider) { Provider otherProvider = (Provider) other; - return otherProvider.thirdPartyId.equals(this.thirdPartyId) && + return Objects.equals(otherProvider.thirdPartyId, this.thirdPartyId) && Objects.equals(otherProvider.name, this.name) && unorderedArrayEquals(otherProvider.clients, this.clients) && Objects.equals(otherProvider.authorizationEndpoint, this.authorizationEndpoint) && @@ -163,7 +244,7 @@ public boolean equals(Object other) { return Objects.equals(otherProviderClient.clientType, this.clientType) && otherProviderClient.clientId.equals(this.clientId) && Objects.equals(otherProviderClient.clientSecret, this.clientSecret) && - Arrays.equals(otherProviderClient.scope, this.scope) && + unorderedArrayEquals(otherProviderClient.scope, this.scope) && otherProviderClient.forcePKCE == this.forcePKCE && Objects.equals(otherProviderClient.additionalConfig, this.additionalConfig); } @@ -223,42 +304,13 @@ public boolean equals(Object other) { } } - public static boolean unorderedArrayEquals(Object[] array1, Object[] array2) { - Set items1 = Set.of(array1); - Set items2 = new HashSet<>(); - items2.addAll(Arrays.asList(array2)); - - - if (items1.size() != items2.size()) return false; - - for (Object p1 : items1) { - boolean found = false; - for (Object p2 : items2) { - if (p1.equals(p2)) { - found = true; - break; - } - } - - if (!found) { - return false; - } else { - items2.remove(p1); - } - } - - return true; - } - @Override public boolean equals(Object other) { if (other instanceof ThirdPartyConfig) { ThirdPartyConfig otherThirdPartyConfig = (ThirdPartyConfig) other; - return otherThirdPartyConfig.enabled == this.enabled && unorderedArrayEquals(this.providers, otherThirdPartyConfig.providers); - } return false; }