From 504c8e336b06c60a1edd87d3049564416acd96bb Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Wed, 1 Nov 2023 16:42:35 +0530 Subject: [PATCH] fix: active users data saved into public tenant storage --- .../supertokens/webserver/WebserverAPI.java | 11 +++ .../api/emailpassword/SignInAPI.java | 2 +- .../api/emailpassword/SignUpAPI.java | 2 +- .../api/passwordless/ConsumeCodeAPI.java | 2 +- .../api/session/RefreshSessionAPI.java | 4 +- .../webserver/api/session/SessionAPI.java | 4 +- .../api/session/SessionRemoveAPI.java | 4 +- .../webserver/api/thirdparty/SignInUpAPI.java | 4 +- .../io/supertokens/test/ActiveUsersTest.java | 81 +++++++++++++++++++ 9 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/supertokens/webserver/WebserverAPI.java b/src/main/java/io/supertokens/webserver/WebserverAPI.java index ea3ac89f4..eca26362d 100644 --- a/src/main/java/io/supertokens/webserver/WebserverAPI.java +++ b/src/main/java/io/supertokens/webserver/WebserverAPI.java @@ -29,6 +29,7 @@ import io.supertokens.pluginInterface.Storage; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; import io.supertokens.pluginInterface.exceptions.StorageQueryException; +import io.supertokens.pluginInterface.multitenancy.AppIdentifier; import io.supertokens.pluginInterface.multitenancy.AppIdentifierWithStorage; import io.supertokens.pluginInterface.multitenancy.TenantIdentifier; import io.supertokens.pluginInterface.multitenancy.TenantIdentifierWithStorage; @@ -340,6 +341,16 @@ protected AppIdentifierWithStorage getAppIdentifierWithStorageFromRequestAndEnfo storage, storages); } + protected AppIdentifierWithStorage getPublicTenantStorage(HttpServletRequest req) + throws ServletException, TenantOrAppNotFoundException { + AppIdentifier appIdentifier = new AppIdentifier(this.getConnectionUriDomain(req), this.getAppId(req)); + + Storage storage = StorageLayer.getStorage(appIdentifier.getAsPublicTenantIdentifier(), main); + + return appIdentifier.withStorage(storage); + + } + protected TenantIdentifierWithStorageAndUserIdMapping getTenantIdentifierWithStorageAndUserIdMappingFromRequest( HttpServletRequest req, String userId, UserIdType userIdType) throws StorageQueryException, TenantOrAppNotFoundException, UnknownUserIdException, ServletException { diff --git a/src/main/java/io/supertokens/webserver/api/emailpassword/SignInAPI.java b/src/main/java/io/supertokens/webserver/api/emailpassword/SignInAPI.java index 5695188da..4074b3ab8 100644 --- a/src/main/java/io/supertokens/webserver/api/emailpassword/SignInAPI.java +++ b/src/main/java/io/supertokens/webserver/api/emailpassword/SignInAPI.java @@ -78,7 +78,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I password); io.supertokens.useridmapping.UserIdMapping.populateExternalUserIdForUsers(tenantIdentifierWithStorage, new AuthRecipeUserInfo[]{user}); - ActiveUsers.updateLastActive(tenantIdentifierWithStorage.toAppIdentifierWithStorage(), main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, user.getSupertokensUserId()); // use the internal user id JsonObject result = new JsonObject(); diff --git a/src/main/java/io/supertokens/webserver/api/emailpassword/SignUpAPI.java b/src/main/java/io/supertokens/webserver/api/emailpassword/SignUpAPI.java index c99791fea..80deeb863 100644 --- a/src/main/java/io/supertokens/webserver/api/emailpassword/SignUpAPI.java +++ b/src/main/java/io/supertokens/webserver/api/emailpassword/SignUpAPI.java @@ -81,7 +81,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I TenantIdentifierWithStorage tenant = this.getTenantIdentifierWithStorageFromRequest(req); AuthRecipeUserInfo user = EmailPassword.signUp(tenant, super.main, normalisedEmail, password); - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, user.getSupertokensUserId()); + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, user.getSupertokensUserId()); JsonObject result = new JsonObject(); result.addProperty("status", "OK"); diff --git a/src/main/java/io/supertokens/webserver/api/passwordless/ConsumeCodeAPI.java b/src/main/java/io/supertokens/webserver/api/passwordless/ConsumeCodeAPI.java index c34aa2fc3..48fbec52b 100644 --- a/src/main/java/io/supertokens/webserver/api/passwordless/ConsumeCodeAPI.java +++ b/src/main/java/io/supertokens/webserver/api/passwordless/ConsumeCodeAPI.java @@ -90,7 +90,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I getVersionFromRequest(req).greaterThanOrEqualTo(SemVer.v4_0)); io.supertokens.useridmapping.UserIdMapping.populateExternalUserIdForUsers(this.getTenantIdentifierWithStorageFromRequest(req), new AuthRecipeUserInfo[]{consumeCodeResponse.user}); - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, consumeCodeResponse.user.getSupertokensUserId()); + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, consumeCodeResponse.user.getSupertokensUserId()); JsonObject result = new JsonObject(); result.addProperty("status", "OK"); diff --git a/src/main/java/io/supertokens/webserver/api/session/RefreshSessionAPI.java b/src/main/java/io/supertokens/webserver/api/session/RefreshSessionAPI.java index ee92da0bd..1749e154b 100644 --- a/src/main/java/io/supertokens/webserver/api/session/RefreshSessionAPI.java +++ b/src/main/java/io/supertokens/webserver/api/session/RefreshSessionAPI.java @@ -90,10 +90,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I this.getAppIdentifierWithStorage(req), sessionInfo.session.userId, UserIdType.ANY); if (userIdMapping != null) { - ActiveUsers.updateLastActive(appIdentifierWithStorage, main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, userIdMapping.superTokensUserId); } else { - ActiveUsers.updateLastActive(appIdentifierWithStorage, main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, sessionInfo.session.userId); } } catch (StorageQueryException ignored) { diff --git a/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java b/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java index 4263285c2..7691ee81e 100644 --- a/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java +++ b/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java @@ -110,10 +110,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I this.getAppIdentifierWithStorage(req), sessionInfo.session.userId, UserIdType.ANY); if (userIdMapping != null) { - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, userIdMapping.superTokensUserId); } else { - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, sessionInfo.session.userId); } } catch (StorageQueryException ignored) { diff --git a/src/main/java/io/supertokens/webserver/api/session/SessionRemoveAPI.java b/src/main/java/io/supertokens/webserver/api/session/SessionRemoveAPI.java index 127e0b5fc..22fba74cf 100644 --- a/src/main/java/io/supertokens/webserver/api/session/SessionRemoveAPI.java +++ b/src/main/java/io/supertokens/webserver/api/session/SessionRemoveAPI.java @@ -116,10 +116,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I this.getAppIdentifierWithStorage(req), userId, UserIdType.ANY); if (userIdMapping != null) { - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, userIdMapping.superTokensUserId); } else { - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, userId); + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, userId); } } catch (StorageQueryException ignored) { } diff --git a/src/main/java/io/supertokens/webserver/api/thirdparty/SignInUpAPI.java b/src/main/java/io/supertokens/webserver/api/thirdparty/SignInUpAPI.java index ad626a64e..caf319f63 100644 --- a/src/main/java/io/supertokens/webserver/api/thirdparty/SignInUpAPI.java +++ b/src/main/java/io/supertokens/webserver/api/thirdparty/SignInUpAPI.java @@ -81,7 +81,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I thirdPartyUserId, email, isEmailVerified); UserIdMapping.populateExternalUserIdForUsers(this.getTenantIdentifierWithStorageFromRequest(req), new AuthRecipeUserInfo[]{response.user}); - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, response.user.getSupertokensUserId()); + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, response.user.getSupertokensUserId()); JsonObject result = new JsonObject(); result.addProperty("status", "OK"); @@ -140,7 +140,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I email, isEmailVerified); UserIdMapping.populateExternalUserIdForUsers(this.getTenantIdentifierWithStorageFromRequest(req), new AuthRecipeUserInfo[]{response.user}); - ActiveUsers.updateLastActive(this.getAppIdentifierWithStorage(req), main, response.user.getSupertokensUserId()); + ActiveUsers.updateLastActive(this.getPublicTenantStorage(req), main, response.user.getSupertokensUserId()); JsonObject result = new JsonObject(); result.addProperty("status", "OK"); diff --git a/src/test/java/io/supertokens/test/ActiveUsersTest.java b/src/test/java/io/supertokens/test/ActiveUsersTest.java index c88a5bbef..108bc38ee 100644 --- a/src/test/java/io/supertokens/test/ActiveUsersTest.java +++ b/src/test/java/io/supertokens/test/ActiveUsersTest.java @@ -4,10 +4,15 @@ import io.supertokens.ActiveUsers; import io.supertokens.Main; import io.supertokens.ProcessState; +import io.supertokens.featureflag.EE_FEATURES; +import io.supertokens.featureflag.FeatureFlagTestContent; import io.supertokens.pluginInterface.STORAGE_TYPE; +import io.supertokens.pluginInterface.multitenancy.TenantIdentifier; import io.supertokens.storageLayer.StorageLayer; import io.supertokens.test.httpRequest.HttpRequestForTesting; import io.supertokens.test.httpRequest.HttpResponseException; +import io.supertokens.test.multitenant.api.TestMultitenancyAPIHelper; +import io.supertokens.utils.SemVer; import org.junit.AfterClass; import org.junit.Before; import org.junit.Rule; @@ -212,4 +217,80 @@ public void activeUserCountAPITest() throws Exception { assert res.get("count").getAsInt() == 2; } + @Test + public void testThatActiveUserDataIsSavedInPublicTenantStorage() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + FeatureFlagTestContent.getInstance(process.getProcess()) + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY}); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + { // Create a tenant + JsonObject coreConfig = new JsonObject(); + + StorageLayer.getStorage(new TenantIdentifier(null, null, null), process.getProcess()) + .modifyConfigToAddANewUserPoolForTesting(coreConfig, 1); + + TestMultitenancyAPIHelper.createTenant( + process.getProcess(), + new TenantIdentifier(null, null, null), + "t1", true, true, true, + coreConfig); + } + + { // no active users yet + HashMap params = new HashMap<>(); + params.put("since", "0"); + JsonObject res = HttpRequestForTesting.sendGETRequest( + process.getProcess(), + "", + "http://localhost:3567/users/count/active", + params, + 1000, + 1000, + null, + Utils.getCdiVersionStringLatestForTests(), + ""); + + assert res.get("status").getAsString().equals("OK"); + assert res.get("count").getAsInt() == 0; + } + + { // Sign up, which updates active users + JsonObject responseBody = new JsonObject(); + responseBody.addProperty("email", "random@gmail.com"); + responseBody.addProperty("password", "validPass123"); + + JsonObject signInResponse = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/t1/recipe/signup", responseBody, 1000, 1000, null, SemVer.v4_0.get(), + "emailpassword"); + } + + { // 1 active user in the public tenant + HashMap params = new HashMap<>(); + params.put("since", "0"); + JsonObject res = HttpRequestForTesting.sendGETRequest( + process.getProcess(), + "", + "http://localhost:3567/users/count/active", + params, + 1000, + 1000, + null, + Utils.getCdiVersionStringLatestForTests(), + ""); + + assert res.get("status").getAsString().equals("OK"); + assert res.get("count").getAsInt() == 1; + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } }