From a107aacbbca8ccc3e285a9e19ffdfdede98f14c4 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Tue, 4 Oct 2022 12:42:06 +0000 Subject: [PATCH 1/8] adds some changes --- .../storage/sql/ConnectionPool.java | 7 ++-- .../io/supertokens/storage/sql/Start.java | 27 +++++++++++++- .../storage/sql/config/Config.java | 17 +++++++-- .../storage/sql/output/Logging.java | 37 +++++++++++++++++-- .../storage/sql/test/LoggingTest.java | 4 +- 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/supertokens/storage/sql/ConnectionPool.java b/src/main/java/io/supertokens/storage/sql/ConnectionPool.java index 91001326..a758c12e 100644 --- a/src/main/java/io/supertokens/storage/sql/ConnectionPool.java +++ b/src/main/java/io/supertokens/storage/sql/ConnectionPool.java @@ -163,7 +163,7 @@ static void initPool(Start start) { if (Thread.currentThread() != start.mainThread) { throw new QuitProgramFromPluginException("Should not come here"); } - Logging.info(start, "Setting up PostgreSQL connection pool."); + Logging.info(start, "Setting up PostgreSQL connection pool.", true); boolean longMessagePrinted = false; long maxTryTime = System.currentTimeMillis() + getTimeToWaitToInit(start); // TODO: sql-plugin -> Form error message based on db being configured.. @@ -183,12 +183,13 @@ static void initPool(Start start) { } if (!longMessagePrinted) { longMessagePrinted = true; - Logging.info(start, errorMessage); + Logging.info(start, errorMessage, true); } double minsRemaining = (maxTryTime - System.currentTimeMillis()) / (1000.0 * 60); NumberFormat formatter = new DecimalFormat("#0.0"); Logging.info(start, - "Trying again in a few seconds for " + formatter.format(minsRemaining) + " mins..."); + "Trying again in a few seconds for " + formatter.format(minsRemaining) + " mins...", + true); try { if (Thread.interrupted()) { throw new InterruptedException(); diff --git a/src/main/java/io/supertokens/storage/sql/Start.java b/src/main/java/io/supertokens/storage/sql/Start.java index 4ede3fd2..43ff8612 100644 --- a/src/main/java/io/supertokens/storage/sql/Start.java +++ b/src/main/java/io/supertokens/storage/sql/Start.java @@ -20,6 +20,7 @@ import ch.qos.logback.classic.Logger; import com.google.gson.JsonObject; import io.supertokens.pluginInterface.KeyValueInfo; +import io.supertokens.pluginInterface.LOG_LEVEL; import io.supertokens.pluginInterface.RECIPE_ID; import io.supertokens.pluginInterface.STORAGE_TYPE; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; @@ -77,7 +78,10 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLTransactionRollbackException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Set; public class Start implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage, @@ -120,8 +124,8 @@ public STORAGE_TYPE getType() { } @Override - public void loadConfig(String configFilePath) { - Config.loadConfig(this, configFilePath); + public void loadConfig(String configFilePath, Set logLevels) { + Config.loadConfig(this, configFilePath, logLevels); } @Override @@ -1746,4 +1750,23 @@ public boolean updateOrDeleteExternalUserIdInfo(String userId, boolean isSuperTo throw new StorageQueryException(e); } } + + @Override + public boolean isUserIdBeingUsedInNonAuthRecipe(String className, String userId) throws StorageQueryException { + // TODO Auto-generated method stub + return false; + } + + @Override + public void addInfoToNonAuthRecipesBasedOnUserId(String className, String userId) throws StorageQueryException { + // TODO Auto-generated method stub + + } + + @Override + public HashMap getUserIdMappingForSuperTokensIds(ArrayList userIds) + throws StorageQueryException { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/main/java/io/supertokens/storage/sql/config/Config.java b/src/main/java/io/supertokens/storage/sql/config/Config.java index 243a9b29..535a176a 100644 --- a/src/main/java/io/supertokens/storage/sql/config/Config.java +++ b/src/main/java/io/supertokens/storage/sql/config/Config.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; + +import io.supertokens.pluginInterface.LOG_LEVEL; import io.supertokens.pluginInterface.exceptions.QuitProgramFromPluginException; import io.supertokens.storage.sql.ResourceDistributor; import io.supertokens.storage.sql.Start; @@ -26,15 +28,18 @@ import java.io.File; import java.io.IOException; +import java.util.Set; public class Config extends ResourceDistributor.SingletonResource { private static final String RESOURCE_KEY = "io.supertokens.storage.sql.config.Config"; private final PostgreSQLConfig config; private final Start start; + private final Set logLevels; - private Config(Start start, String configFilePath) { + private Config(Start start, String configFilePath, Set logLevels) { this.start = start; + this.logLevels = logLevels; try { config = loadPostgreSQLConfig(configFilePath); } catch (IOException e) { @@ -46,12 +51,12 @@ private static Config getInstance(Start start) { return (Config) start.getResourceDistributor().getResource(RESOURCE_KEY); } - public static void loadConfig(Start start, String configFilePath) { + public static void loadConfig(Start start, String configFilePath, Set logLevels) { if (getInstance(start) != null) { return; } - Logging.info(start, "Loading PostgreSQL config."); - start.getResourceDistributor().setResource(RESOURCE_KEY, new Config(start, configFilePath)); + start.getResourceDistributor().setResource(RESOURCE_KEY, new Config(start, configFilePath, logLevels)); + Logging.info(start, "Loading PostgreSQL config.", true); } public static PostgreSQLConfig getConfig(Start start) { @@ -61,6 +66,10 @@ public static PostgreSQLConfig getConfig(Start start) { return getInstance(start).config; } + public static Set getLogLevels(Start start) { + return getInstance(start).logLevels; + } + private PostgreSQLConfig loadPostgreSQLConfig(String configFilePath) throws IOException { final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); PostgreSQLConfig config = mapper.readValue(new File(configFilePath), PostgreSQLConfig.class); diff --git a/src/main/java/io/supertokens/storage/sql/output/Logging.java b/src/main/java/io/supertokens/storage/sql/output/Logging.java index 6a29095a..ad2e9ca7 100644 --- a/src/main/java/io/supertokens/storage/sql/output/Logging.java +++ b/src/main/java/io/supertokens/storage/sql/output/Logging.java @@ -22,8 +22,10 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.FileAppender; +import io.supertokens.pluginInterface.LOG_LEVEL; import io.supertokens.storage.sql.ResourceDistributor; import io.supertokens.storage.sql.Start; +import io.supertokens.storage.sql.config.Config; import io.supertokens.storage.sql.utils.Utils; import org.slf4j.LoggerFactory; @@ -48,11 +50,14 @@ private static Logging getInstance(Start start) { public static void initFileLogging(Start start, String infoLogPath, String errorLogPath) { if (getInstance(start) == null) { start.getResourceDistributor().setResource(RESOURCE_ID, new Logging(start, infoLogPath, errorLogPath)); - } } public static void debug(Start start, String msg) { + if (!Config.getLogLevels(start).contains(LOG_LEVEL.DEBUG)) { + return; + } + try { msg = msg.trim(); if (getInstance(start) != null) { @@ -62,18 +67,26 @@ public static void debug(Start start, String msg) { } } - public static void info(Start start, String msg) { + public static void info(Start start, String msg, boolean toConsoleAsWell) { + if (!Config.getLogLevels(start).contains(LOG_LEVEL.INFO)) { + return; + } try { msg = msg.trim(); - systemOut(msg); if (getInstance(start) != null) { getInstance(start).infoLogger.info(msg); } + if (toConsoleAsWell) { + systemOut(msg); + } } catch (NullPointerException ignored) { } } public static void warn(Start start, String msg) { + if (!Config.getLogLevels(start).contains(LOG_LEVEL.WARN)) { + return; + } try { msg = msg.trim(); if (getInstance(start) != null) { @@ -84,6 +97,15 @@ public static void warn(Start start, String msg) { } public static void error(Start start, String err, boolean toConsoleAsWell) { + try { + if (!Config.getLogLevels(start).contains(LOG_LEVEL.ERROR)) { + return; + } + } catch (Throwable ignored) { + // if it comes here, it means that the config was not loaded and that we are trying + // to log some other error. In this case, we want to log it anyway, so we catch any + // error and continue below. + } try { err = err.trim(); if (getInstance(start) != null) { @@ -97,6 +119,15 @@ public static void error(Start start, String err, boolean toConsoleAsWell) { } public static void error(Start start, String message, boolean toConsoleAsWell, Exception e) { + try { + if (!Config.getLogLevels(start).contains(LOG_LEVEL.ERROR)) { + return; + } + } catch (Throwable ignored) { + // if it comes here, it means that the config was not loaded and that we are trying + // to log some other error. In this case, we want to log it anyway, so we catch any + // error and continue below. + } try { String err = Utils.exceptionStacktraceToString(e).trim(); if (getInstance(start) != null) { diff --git a/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java b/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java index 8898abe2..03dd9025 100644 --- a/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java +++ b/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java @@ -63,7 +63,7 @@ public void defaultLogging() throws Exception { File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "From Test", false); - Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "From Info"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "From Info", true); boolean infoFlag = false; boolean errorFlag = false; @@ -106,7 +106,7 @@ public void customLogging() throws Exception { assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "From Test", false); - Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "From Info"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "From Info", true); boolean infoFlag = false; boolean errorFlag = false; From 6a4dccbaf2bbca47e8ee7e75ae6df07e75366197 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Thu, 6 Oct 2022 12:09:44 +0000 Subject: [PATCH 2/8] updates column size --- .../supertokens/storage/sql/queries/EmailPasswordQueries.java | 2 +- .../io/supertokens/storage/sql/queries/ThirdPartyQueries.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/supertokens/storage/sql/queries/EmailPasswordQueries.java b/src/main/java/io/supertokens/storage/sql/queries/EmailPasswordQueries.java index 986b71cd..b3e29678 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/EmailPasswordQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/EmailPasswordQueries.java @@ -51,7 +51,7 @@ static String getQueryToCreateUsersTable(Start start) { + "user_id CHAR(36) NOT NULL," + "email VARCHAR(256) NOT NULL CONSTRAINT " + Utils.getConstraintName(schema, emailPasswordUsersTable, "email", "key") + " UNIQUE," - + "password_hash VARCHAR(128) NOT NULL," + "time_joined BIGINT NOT NULL," + + "password_hash VARCHAR(256) NOT NULL," + "time_joined BIGINT NOT NULL," + "CONSTRAINT " + Utils.getConstraintName(schema, emailPasswordUsersTable, null, "pkey") + " PRIMARY KEY (user_id));"; // @formatter:on diff --git a/src/main/java/io/supertokens/storage/sql/queries/ThirdPartyQueries.java b/src/main/java/io/supertokens/storage/sql/queries/ThirdPartyQueries.java index f594e659..3a087b16 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/ThirdPartyQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/ThirdPartyQueries.java @@ -46,7 +46,7 @@ static String getQueryToCreateUsersTable(Start start) { // @formatter:off return "CREATE TABLE IF NOT EXISTS " + thirdPartyUsersTable + " (" + "third_party_id VARCHAR(28) NOT NULL," - + "third_party_user_id VARCHAR(128) NOT NULL," + + "third_party_user_id VARCHAR(256) NOT NULL," + "user_id CHAR(36) NOT NULL CONSTRAINT " + Utils.getConstraintName(schema, thirdPartyUsersTable, "user_id", "key") + " UNIQUE," + "email VARCHAR(256) NOT NULL," From 0f81e6947d54939a39fbb4bfc2ca7c720ce49130 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Fri, 7 Oct 2022 07:35:17 +0000 Subject: [PATCH 3/8] adds log level tests --- .../storage/sql/test/LogLevelTest.java | 310 ++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 src/test/java/io/supertokens/storage/sql/test/LogLevelTest.java diff --git a/src/test/java/io/supertokens/storage/sql/test/LogLevelTest.java b/src/test/java/io/supertokens/storage/sql/test/LogLevelTest.java new file mode 100644 index 00000000..bbd90644 --- /dev/null +++ b/src/test/java/io/supertokens/storage/sql/test/LogLevelTest.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2020, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ + +package io.supertokens.storage.sql.test; + +import io.supertokens.ProcessState; +import io.supertokens.config.Config; +import io.supertokens.storage.sql.Start; +import io.supertokens.storage.sql.output.Logging; +import io.supertokens.storageLayer.StorageLayer; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; + +import static org.junit.Assert.*; + +public class LogLevelTest { + @Rule + public TestRule watchman = Utils.getOnFailure(); + + @AfterClass + public static void afterTesting() { + Utils.afterTesting(); + } + + @Before + public void beforeEach() { + Utils.reset(); + } + + @Test + public void testLogLevelNoneOutput() throws Exception { + { + Utils.setValueInConfig("log_level", "NONE"); + String[] args = { "../" }; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + File infoLog = new File(Config.getConfig(process.getProcess()).getInfoLogPath(process.getProcess())); + File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); + boolean didOutput = false; + Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "some message", false); + Logging.warn((Start) StorageLayer.getStorage(process.getProcess()), "some message"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "some message", true); + Logging.debug((Start) StorageLayer.getStorage(process.getProcess()), "some message"); + + try (Scanner scanner = new Scanner(infoLog, StandardCharsets.UTF_8)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + didOutput = true; + break; + } + } + } + + try (Scanner errorScanner = new Scanner(errorLog, StandardCharsets.UTF_8)) { + while (errorScanner.hasNextLine()) { + String line = errorScanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + didOutput = true; + break; + } + } + } + + assertFalse(didOutput); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } + + @Test + public void testLogLevelErrorOutput() throws Exception { + { + Utils.setValueInConfig("log_level", "ERROR"); + String[] args = { "../" }; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + File infoLog = new File(Config.getConfig(process.getProcess()).getInfoLogPath(process.getProcess())); + File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); + boolean errorOutput = false; + boolean warnOutput = false; + boolean infoOutput = false; + boolean debugOutput = false; + + Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "some error", false); + Logging.warn((Start) StorageLayer.getStorage(process.getProcess()), "some warn"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "some info", true); + Logging.debug((Start) StorageLayer.getStorage(process.getProcess()), "some debug"); + + try (Scanner scanner = new Scanner(infoLog, StandardCharsets.UTF_8)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some info")) { + infoOutput = true; + } else if (line.contains("some debug")) { + debugOutput = true; + } + } + } + } + + try (Scanner errorScanner = new Scanner(errorLog, StandardCharsets.UTF_8)) { + while (errorScanner.hasNextLine()) { + String line = errorScanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some error")) { + errorOutput = true; + } else if (line.contains("some warn")) { + warnOutput = true; + } + } + } + } + + assertTrue(errorOutput && !warnOutput && !infoOutput && !debugOutput); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } + + @Test + public void testLogLevelWarnOutput() throws Exception { + { + Utils.setValueInConfig("log_level", "WARN"); + String[] args = { "../" }; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + File infoLog = new File(Config.getConfig(process.getProcess()).getInfoLogPath(process.getProcess())); + File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); + boolean errorOutput = false; + boolean warnOutput = false; + boolean infoOutput = false; + boolean debugOutput = false; + + Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "some error", false); + Logging.warn((Start) StorageLayer.getStorage(process.getProcess()), "some warn"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "some info", true); + Logging.debug((Start) StorageLayer.getStorage(process.getProcess()), "some debug"); + + try (Scanner scanner = new Scanner(infoLog, StandardCharsets.UTF_8)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some info")) { + infoOutput = true; + } else if (line.contains("some debug")) { + debugOutput = true; + } + } + } + } + + try (Scanner errorScanner = new Scanner(errorLog, StandardCharsets.UTF_8)) { + while (errorScanner.hasNextLine()) { + String line = errorScanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some error")) { + errorOutput = true; + } else if (line.contains("some warn")) { + warnOutput = true; + } + } + } + } + + assertTrue(errorOutput && warnOutput && !infoOutput && !debugOutput); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } + + @Test + public void testLogLevelInfoOutput() throws Exception { + { + Utils.setValueInConfig("log_level", "INFO"); + String[] args = { "../" }; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + File infoLog = new File(Config.getConfig(process.getProcess()).getInfoLogPath(process.getProcess())); + File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); + boolean errorOutput = false; + boolean warnOutput = false; + boolean infoOutput = false; + boolean debugOutput = false; + + Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "some error", false); + Logging.warn((Start) StorageLayer.getStorage(process.getProcess()), "some warn"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "some info", true); + Logging.debug((Start) StorageLayer.getStorage(process.getProcess()), "some debug"); + + try (Scanner scanner = new Scanner(infoLog, StandardCharsets.UTF_8)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some info")) { + infoOutput = true; + } else if (line.contains("some debug")) { + debugOutput = true; + } + } + } + } + + try (Scanner errorScanner = new Scanner(errorLog, StandardCharsets.UTF_8)) { + while (errorScanner.hasNextLine()) { + String line = errorScanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some error")) { + errorOutput = true; + } else if (line.contains("some warn")) { + warnOutput = true; + } + } + } + } + + assertTrue(errorOutput && warnOutput && infoOutput && !debugOutput); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } + + @Test + public void testLogLevelDebugOutput() throws Exception { + { + Utils.setValueInConfig("log_level", "DEBUG"); + String[] args = { "../" }; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + File infoLog = new File(Config.getConfig(process.getProcess()).getInfoLogPath(process.getProcess())); + File errorLog = new File(Config.getConfig(process.getProcess()).getErrorLogPath(process.getProcess())); + boolean errorOutput = false; + boolean warnOutput = false; + boolean infoOutput = false; + boolean debugOutput = false; + + Logging.error((Start) StorageLayer.getStorage(process.getProcess()), "some error", false); + Logging.warn((Start) StorageLayer.getStorage(process.getProcess()), "some warn"); + Logging.info((Start) StorageLayer.getStorage(process.getProcess()), "some info", true); + Logging.debug((Start) StorageLayer.getStorage(process.getProcess()), "some debug"); + + try (Scanner scanner = new Scanner(infoLog, StandardCharsets.UTF_8)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some info")) { + infoOutput = true; + } else if (line.contains("some debug")) { + debugOutput = true; + } + } + } + } + + try (Scanner errorScanner = new Scanner(errorLog, StandardCharsets.UTF_8)) { + while (errorScanner.hasNextLine()) { + String line = errorScanner.nextLine(); + if (line.contains(process.getProcess().getProcessId())) { + if (line.contains("some error")) { + errorOutput = true; + } else if (line.contains("some warn")) { + warnOutput = true; + } + } + } + } + + assertTrue(errorOutput && warnOutput && infoOutput && debugOutput); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } +} \ No newline at end of file From 1a0207afffea1a4ca6e10b1bff3474799c95f813 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Mon, 10 Oct 2022 06:38:37 +0000 Subject: [PATCH 4/8] adds remaining userId mapping changes --- .../io/supertokens/storage/sql/Start.java | 77 ++++++++++++++++++- .../sql/queries/EmailVerificationQueries.java | 12 +++ .../sql/queries/UserIdMappingQueries.java | 38 +++++++++ 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/supertokens/storage/sql/Start.java b/src/main/java/io/supertokens/storage/sql/Start.java index 43ff8612..90d25e25 100644 --- a/src/main/java/io/supertokens/storage/sql/Start.java +++ b/src/main/java/io/supertokens/storage/sql/Start.java @@ -31,12 +31,14 @@ import io.supertokens.pluginInterface.emailpassword.exceptions.DuplicateUserIdException; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; import io.supertokens.pluginInterface.emailpassword.sqlStorage.EmailPasswordSQLStorage; +import io.supertokens.pluginInterface.emailverification.EmailVerificationStorage; import io.supertokens.pluginInterface.emailverification.EmailVerificationTokenInfo; import io.supertokens.pluginInterface.emailverification.exception.DuplicateEmailVerificationTokenException; import io.supertokens.pluginInterface.emailverification.sqlStorage.EmailVerificationSQLStorage; import io.supertokens.pluginInterface.exceptions.QuitProgramFromPluginException; import io.supertokens.pluginInterface.exceptions.StorageQueryException; import io.supertokens.pluginInterface.exceptions.StorageTransactionLogicException; +import io.supertokens.pluginInterface.jwt.JWTRecipeStorage; import io.supertokens.pluginInterface.jwt.JWTSigningKeyInfo; import io.supertokens.pluginInterface.jwt.exceptions.DuplicateKeyIdException; import io.supertokens.pluginInterface.jwt.sqlstorage.JWTRecipeSQLStorage; @@ -45,6 +47,7 @@ import io.supertokens.pluginInterface.passwordless.exception.*; import io.supertokens.pluginInterface.passwordless.sqlStorage.PasswordlessSQLStorage; import io.supertokens.pluginInterface.session.SessionInfo; +import io.supertokens.pluginInterface.session.SessionStorage; import io.supertokens.pluginInterface.session.sqlStorage.SessionSQLStorage; import io.supertokens.pluginInterface.sqlStorage.TransactionConnection; import io.supertokens.pluginInterface.thirdparty.exception.DuplicateThirdPartyUserException; @@ -53,7 +56,9 @@ import io.supertokens.pluginInterface.useridmapping.UserIdMappingStorage; import io.supertokens.pluginInterface.useridmapping.exception.UnknownSuperTokensUserIdException; import io.supertokens.pluginInterface.useridmapping.exception.UserIdMappingAlreadyExistsException; +import io.supertokens.pluginInterface.usermetadata.UserMetadataStorage; import io.supertokens.pluginInterface.usermetadata.sqlStorage.UserMetadataSQLStorage; +import io.supertokens.pluginInterface.userroles.UserRolesStorage; import io.supertokens.pluginInterface.userroles.exception.DuplicateUserRoleMappingException; import io.supertokens.pluginInterface.userroles.exception.UnknownRoleException; import io.supertokens.pluginInterface.userroles.sqlStorage.UserRolesSQLStorage; @@ -1753,13 +1758,79 @@ public boolean updateOrDeleteExternalUserIdInfo(String userId, boolean isSuperTo @Override public boolean isUserIdBeingUsedInNonAuthRecipe(String className, String userId) throws StorageQueryException { - // TODO Auto-generated method stub - return false; + // check if the input userId is being used in nonAuthRecipes. + if (className.equals(SessionStorage.class.getName())) { + String[] sessionHandlesForUser = getAllNonExpiredSessionHandlesForUser(userId); + return sessionHandlesForUser.length > 0; + } else if (className.equals(UserRolesStorage.class.getName())) { + String[] roles = getRolesForUser(userId); + return roles.length > 0; + } else if (className.equals(UserMetadataStorage.class.getName())) { + JsonObject userMetadata = getUserMetadata(userId); + return userMetadata != null; + } else if (className.equals(EmailVerificationStorage.class.getName())) { + try { + return EmailVerificationQueries.isUserIdBeingUsedForEmailVerification(this, userId); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } else if (className.equals(JWTRecipeSQLStorage.class.getName())) { + return false; + } else { + throw new IllegalStateException("ClassName: " + className + " is not part of NonAuthRecipeStorage"); + } } @Override public void addInfoToNonAuthRecipesBasedOnUserId(String className, String userId) throws StorageQueryException { - // TODO Auto-generated method stub + // add entries to nonAuthRecipe tables with input userId + if (className.equals(SessionStorage.class.getName())) { + try { + createNewSession("sessionHandle", userId, "refreshTokenHash", new JsonObject(), + System.currentTimeMillis() + 1000000, new JsonObject(), System.currentTimeMillis()); + } catch (Exception e) { + throw new StorageQueryException(e); + } + } else if (className.equals(UserRolesStorage.class.getName())) { + try { + String role = "testRole"; + this.startTransaction(con -> { + createNewRoleOrDoNothingIfExists_Transaction(con, role); + return null; + }); + try { + addRoleToUser(userId, role); + } catch (Exception e) { + throw new StorageTransactionLogicException(e); + } + } catch (StorageTransactionLogicException e) { + throw new StorageQueryException(e.actualException); + } + } else if (className.equals(EmailVerificationStorage.class.getName())) { + try { + EmailVerificationTokenInfo info = new EmailVerificationTokenInfo(userId, "someToken", 10000, + "test123@example.com"); + addEmailVerificationToken(info); + + } catch (DuplicateEmailVerificationTokenException e) { + throw new StorageQueryException(e); + } + } else if (className.equals(UserMetadataStorage.class.getName())) { + JsonObject data = new JsonObject(); + data.addProperty("test", "testData"); + try { + this.startTransaction(con -> { + setUserMetadata_Transaction(con, userId, data); + return null; + }); + } catch (StorageTransactionLogicException e) { + throw new StorageQueryException(e); + } + } else if (className.equals(JWTRecipeStorage.class.getName())) { + /* Since JWT recipe tables do not store userId we do not add any data to them */ + } else { + throw new IllegalStateException("ClassName: " + className + " is not part of NonAuthRecipeStorage"); + } } diff --git a/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java b/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java index d604873c..c474bc89 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java @@ -70,6 +70,18 @@ static String getQueryToCreateEmailVerificationTokenExpiryIndex(Start start) { + Config.getConfig(start).getEmailVerificationTokensTable() + "(token_expiry);"; } + public static boolean isUserIdBeingUsedForEmailVerification(Start start, String userId) + throws SQLException, StorageQueryException { + + return ConnectionPool.withSession(start, (session, con) -> { + String QUERY = "SELECT * FROM EmailVerificationDo WHERE entity.pk.user.user_id = :userId"; + CustomQueryWrapper q = session.createQuery(QUERY, EmailVerificationDO.class); + q.setParameter("user_id", userId); + List result = q.list(); + return result.size() > 0; + }, false); + } + public static void deleteExpiredEmailVerificationTokens(Start start) throws SQLException, StorageQueryException { ConnectionPool.withSession(start, (session, con) -> { String QUERY = "DELETE FROM EmailVerificationTokensDO where token_expiry < :expiry"; diff --git a/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java b/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java index d38b8a65..5d203301 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java @@ -29,6 +29,8 @@ import javax.annotation.Nullable; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class UserIdMappingQueries { @@ -123,6 +125,42 @@ public static UserIdMapping[] getUserIdMappingWithSuperTokensUserIdOrExternalUse } + public static HashMap getUserIdMappingWithUserIds(Start start, ArrayList userIds) + throws SQLException, StorageQueryException { + + if (userIds.size() == 0) { + return new HashMap<>(); + } + + List mappingsFromQuery = ConnectionPool.withSession(start, (session, con) -> { + CustomQueryWrapper q; + StringBuilder userIdCondition = new StringBuilder(); + + userIdCondition.append("entity.pk.user.user_id IN (:user_ids);"); + + String userIdConditionAsString = userIdCondition.toString(); + + String QUERY = "SELECT entity FROM UserIdMappingDO entity WHERE " + userIdConditionAsString; + + String[] userIdsToIncludeStr = new String[userIds.size()]; + for (int i = 0; i < userIds.size(); i++) { + userIdsToIncludeStr[i] = userIds.get(i).toString(); + } + + q = session.createQuery(QUERY, UserIdMappingDO.class); + q.setParameterList("user_ids", userIdsToIncludeStr); + return q.list(); + }, false); + + HashMap userIdMappings = new HashMap<>(); + for (int i = 0; i < mappingsFromQuery.size(); i++) { + userIdMappings.put(mappingsFromQuery.get(i).getPk().getSuperTokensUserId(), + mappingsFromQuery.get(i).getPk().getSuperTokensUserId()); + } + + return userIdMappings; + } + public static boolean deleteUserIdMappingWithSuperTokensUserId(Start start, String userId) throws SQLException, StorageQueryException { return ConnectionPool.withSession(start, (session, con) -> { From d034739dc94547887f7954032bf7278539bb1a9d Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Mon, 10 Oct 2022 09:29:19 +0000 Subject: [PATCH 5/8] query fixes --- src/main/java/io/supertokens/storage/sql/Start.java | 2 +- .../storage/sql/queries/EmailVerificationQueries.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/supertokens/storage/sql/Start.java b/src/main/java/io/supertokens/storage/sql/Start.java index 90d25e25..a60f70d9 100644 --- a/src/main/java/io/supertokens/storage/sql/Start.java +++ b/src/main/java/io/supertokens/storage/sql/Start.java @@ -1774,7 +1774,7 @@ public boolean isUserIdBeingUsedInNonAuthRecipe(String className, String userId) } catch (SQLException e) { throw new StorageQueryException(e); } - } else if (className.equals(JWTRecipeSQLStorage.class.getName())) { + } else if (className.equals(JWTRecipeStorage.class.getName())) { return false; } else { throw new IllegalStateException("ClassName: " + className + " is not part of NonAuthRecipeStorage"); diff --git a/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java b/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java index c474bc89..8c0619e8 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/EmailVerificationQueries.java @@ -74,10 +74,11 @@ public static boolean isUserIdBeingUsedForEmailVerification(Start start, String throws SQLException, StorageQueryException { return ConnectionPool.withSession(start, (session, con) -> { - String QUERY = "SELECT * FROM EmailVerificationDo WHERE entity.pk.user.user_id = :userId"; - CustomQueryWrapper q = session.createQuery(QUERY, EmailVerificationDO.class); - q.setParameter("user_id", userId); - List result = q.list(); + String QUERY = "SELECT entity FROM EmailVerificationTokensDO entity WHERE entity.pk.user_id = :userId"; + CustomQueryWrapper q = session.createQuery(QUERY, + EmailVerificationTokensDO.class); + q.setParameter("userId", userId); + List result = q.list(); return result.size() > 0; }, false); } From a2f4017d42f4ade2ce9ce015fa43d88ab2d69e6a Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Mon, 10 Oct 2022 10:47:35 +0000 Subject: [PATCH 6/8] fixes --- src/main/java/io/supertokens/storage/sql/Start.java | 7 +++++-- .../storage/sql/queries/UserIdMappingQueries.java | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/supertokens/storage/sql/Start.java b/src/main/java/io/supertokens/storage/sql/Start.java index a60f70d9..6830d96c 100644 --- a/src/main/java/io/supertokens/storage/sql/Start.java +++ b/src/main/java/io/supertokens/storage/sql/Start.java @@ -1837,7 +1837,10 @@ public void addInfoToNonAuthRecipesBasedOnUserId(String className, String userId @Override public HashMap getUserIdMappingForSuperTokensIds(ArrayList userIds) throws StorageQueryException { - // TODO Auto-generated method stub - return null; + try { + return UserIdMappingQueries.getUserIdMappingWithUserIds(this, userIds); + } catch (SQLException e) { + throw new StorageQueryException(e); + } } } diff --git a/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java b/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java index 5d203301..cc81475c 100644 --- a/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java +++ b/src/main/java/io/supertokens/storage/sql/queries/UserIdMappingQueries.java @@ -136,7 +136,7 @@ public static HashMap getUserIdMappingWithUserIds(Start start, A CustomQueryWrapper q; StringBuilder userIdCondition = new StringBuilder(); - userIdCondition.append("entity.pk.user.user_id IN (:user_ids);"); + userIdCondition.append("entity.pk.user.user_id IN (:user_ids)"); String userIdConditionAsString = userIdCondition.toString(); @@ -155,7 +155,7 @@ public static HashMap getUserIdMappingWithUserIds(Start start, A HashMap userIdMappings = new HashMap<>(); for (int i = 0; i < mappingsFromQuery.size(); i++) { userIdMappings.put(mappingsFromQuery.get(i).getPk().getSuperTokensUserId(), - mappingsFromQuery.get(i).getPk().getSuperTokensUserId()); + mappingsFromQuery.get(i).getPk().getExternal_user_id()); } return userIdMappings; From ee25f80b599c81cfe3fd56dec0d438ff221c0f35 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Mon, 10 Oct 2022 12:16:36 +0000 Subject: [PATCH 7/8] updates CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index beacc903..99c74e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Updates `password_hash` and `third_party_user_id` column sizes +- Adds remaining changes for UserId mapping queries +- Adds LOG_LEVEL support - Sets up SessionFactory connection and modifies how initial connection retries are done. - Sets up logging handlers for hibernate and jboss - Adds hibernate dependencies to build.gradle and modifies the implementationDependencies.json file From f98dee8fa8f45aef511233022b61d68341b60c39 Mon Sep 17 00:00:00 2001 From: Joel Coutinho Date: Mon, 10 Oct 2022 13:35:29 +0000 Subject: [PATCH 8/8] adds missing test config --- src/test/java/io/supertokens/storage/sql/test/LoggingTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java b/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java index 03dd9025..5a8f31f9 100644 --- a/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java +++ b/src/test/java/io/supertokens/storage/sql/test/LoggingTest.java @@ -208,6 +208,7 @@ public void testStandardOutLoggingWithNullStr() throws Exception { ByteArrayOutputStream stdOutput = new ByteArrayOutputStream(); ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); + Utils.setValueInConfig("log_level", "DEBUG"); Utils.setValueInConfig("info_log_path", "\"null\""); Utils.setValueInConfig("error_log_path", "\"null\""); @@ -243,6 +244,7 @@ public void testStandardOutLoggingWithNull() throws Exception { ByteArrayOutputStream stdOutput = new ByteArrayOutputStream(); ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); + Utils.setValueInConfig("log_level", "DEBUG"); Utils.setValueInConfig("info_log_path", "null"); Utils.setValueInConfig("error_log_path", "null");