Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ core_config_version: 0
# their tenants. It only exposes that information when this key is used instead of the regular api_keys config.
# supertokens_saas_secret:

# (OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version when CDI version is not
# specified in the request. When set to null, the core will assume the latest version of the CDI.
# (DIFFERENT_ACROSS_APPS | OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version
# when CDI version is not specified in the request. When set to null, the core will assume the latest version of the
# CDI.
# supertokens_default_cdi_version:
5 changes: 3 additions & 2 deletions devConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ disable_telemetry: true
# their tenants. It only exposes that information when this key is used instead of the regular api_keys config.
# supertokens_saas_secret:

# (OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version when CDI version is not
# specified in the request. When set to null, the core will assume the latest version of the CDI.
# (DIFFERENT_ACROSS_APPS | OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version
# when CDI version is not specified in the request. When set to null, the core will assume the latest version of the
# CDI.
# supertokens_default_cdi_version:
2 changes: 1 addition & 1 deletion src/main/java/io/supertokens/config/CoreConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public class CoreConfig {
@JsonProperty
private String supertokens_saas_secret = null;

@ConfigYamlOnly
@NotConflictingInApp
@JsonProperty
private String supertokens_default_cdi_version = null;

Expand Down
13 changes: 9 additions & 4 deletions src/main/java/io/supertokens/webserver/WebserverAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,21 @@ protected String getRIDFromRequest(HttpServletRequest req) {
return req.getHeader("rId");
}

protected SemVer getVersionFromRequest(HttpServletRequest req) {
protected SemVer getVersionFromRequest(HttpServletRequest req) throws ServletException {
String version = req.getHeader("cdi-version");

if (version != null) {
return new SemVer(version);
}

String defaultCDIVersion = Config.getBaseConfig(main).getDefaultCDIVersion();
if (defaultCDIVersion != null) {
return new SemVer(defaultCDIVersion);
try {
String defaultCDIVersion = Config.getConfig(
getAppIdentifierWithStorage(req).getAsPublicTenantIdentifier(), main).getDefaultCDIVersion();
if (defaultCDIVersion != null) {
return new SemVer(defaultCDIVersion);
}
} catch (TenantOrAppNotFoundException e) {
throw new ServletException(e);
}

return getLatestCDIVersion();
Expand Down
91 changes: 87 additions & 4 deletions src/test/java/io/supertokens/test/CDIVersionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.supertokens.ProcessState;
import io.supertokens.featureflag.EE_FEATURES;
import io.supertokens.featureflag.FeatureFlagTestContent;
import io.supertokens.httpRequest.HttpRequest;
import io.supertokens.multitenancy.Multitenancy;
import io.supertokens.pluginInterface.multitenancy.*;
import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
import io.supertokens.test.httpRequest.HttpRequestForTesting;
import io.supertokens.utils.SemVer;
import io.supertokens.webserver.Webserver;
import io.supertokens.webserver.WebserverAPI;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.AfterClass;
Expand All @@ -33,6 +39,7 @@
import org.junit.rules.TestRule;

import java.io.IOException;
import java.rmi.ServerException;
import java.util.HashMap;

import static junit.framework.TestCase.assertEquals;
Expand Down Expand Up @@ -73,7 +80,8 @@ public String getPath() {
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
SemVer version = getVersionFromRequest(req);

super.sendTextResponse(200, version.toString(), resp);
Expand Down Expand Up @@ -110,7 +118,8 @@ public String getPath() {
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
SemVer version = getVersionFromRequest(req);

super.sendTextResponse(200, version.toString(), resp);
Expand Down Expand Up @@ -156,7 +165,8 @@ public String getPath() {
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
SemVer version = getVersionFromRequest(req);

super.sendTextResponse(200, version.toString(), resp);
Expand Down Expand Up @@ -197,7 +207,8 @@ public String getPath() {
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
SemVer version = getVersionFromRequest(req);

super.sendTextResponse(200, version.toString(), resp);
Expand All @@ -213,6 +224,78 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IO
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

@Test
public void testCDIVersionWorksPerApp() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
Utils.setValueInConfig("supertokens_default_cdi_version", "2.21");
FeatureFlagTestContent.getInstance(process.getProcess())
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY});
process.startProcess();

assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") {

private static final long serialVersionUID = 1L;

@Override
public boolean checkAPIKey(HttpServletRequest req) {
return false;
}

@Override
public String getPath() {
return "/version-test";
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
SemVer version = getVersionFromRequest(req);

super.sendTextResponse(200, version.toString(), resp);
}
});

JsonObject config = new JsonObject();
config.addProperty("supertokens_default_cdi_version", "3.0");
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, "a1", null),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, "a1", "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
new JsonObject()
), false);

String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null,
null, "");
assertEquals("2.21", response);

response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/appid-a1/version-test", new HashMap<>(), 1000, 1000, null,
null, "");
assertEquals("3.0", response);

response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/appid-a1/t1/version-test", new HashMap<>(), 1000, 1000, null,
null, "");
assertEquals("3.0", response);

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));

}

@Test
public void testJWKSEndpointWorksInAllCases() throws Exception {
{
Expand Down
8 changes: 4 additions & 4 deletions src/test/java/io/supertokens/test/multitenant/ConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1909,8 +1909,7 @@ public void testAllConflictingConfigs() throws Exception {
"argon2_hashing_pool_size",
"log_level",
"firebase_password_hashing_pool_size",
"supertokens_saas_secret",
"supertokens_default_cdi_version"
"supertokens_saas_secret"
};
Object[] disallowedValues = new Object[]{
3567,
Expand All @@ -1922,8 +1921,7 @@ public void testAllConflictingConfigs() throws Exception {
12,
"DEBUG",
12,
"abcd1234abcd1234",
"3.0"
"abcd1234abcd1234"
};

process.kill();
Expand Down Expand Up @@ -1981,6 +1979,7 @@ public void testAllConflictingConfigs() throws Exception {
"argon2_parallelism",
"bcrypt_log_rounds",
"firebase_password_hashing_signer_key",
"supertokens_default_cdi_version",
};
Object[][] conflictingValues = new Object[][]{
new Object[]{3600, 3601}, // access_token_validity
Expand All @@ -1996,6 +1995,7 @@ public void testAllConflictingConfigs() throws Exception {
new Object[]{2, 3}, // argon2_parallelism
new Object[]{11, 12}, // bcrypt_log_rounds
new Object[]{"abcd1234abcd1234abcd1234abcd1234", "qwer1234qwer1234qwer1234qwer1234"}, // firebase_password_hashing_signer_key
new Object[]{"2.21", "3.0"} // supertokens_default_cdi_version
};

for (int i=0; i<conflictingInSameUserPool.length; i++) {
Expand Down