Skip to content

Commit

Permalink
Merge branch '5.0' into feat/mfa
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Feb 27, 2024
2 parents 87e64f2 + 969b945 commit c494041
Show file tree
Hide file tree
Showing 15 changed files with 802 additions and 30 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- This enables smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to
change the signing key type of a session

## [5.0.8] - 2024-02-19

- Fixes vulnerabilities in dependencies

## [5.0.7] - 2024-01-25

- Fixes the issue where passwords were inadvertently logged in the logs.
- Adds tests to check connection pool behaviour.
- Adds `postgresql_idle_connection_timeout` and `postgresql_minimum_idle_connections` configs to control active connections to the database.

## [5.0.6] - 2023-12-05

- Validates db config types in `canBeUsed` function
Expand Down
18 changes: 9 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id 'java-library'
}

version = "5.0.6"
version = "5.0.8"

repositories {
mavenCentral()
Expand All @@ -17,16 +17,16 @@ dependencies {
implementation group: 'com.zaxxer', name: 'HikariCP', version: '3.4.1'

// https://mvnrepository.com/artifact/org.postgresql/postgresql
implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.10'
implementation group: 'org.postgresql', name: 'postgresql', version: '42.7.2'

// https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml
compileOnly group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.14.0'
compileOnly group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.16.1'

// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.14.0'
compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.16.1'

// https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
compileOnly group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
compileOnly group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14'

// https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305
compileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
Expand All @@ -43,21 +43,21 @@ dependencies {
testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.1.0'

// https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core
testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '10.1.1'
testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '10.1.18'

// https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14'

// https://mvnrepository.com/artifact/com.google.code.gson/gson
testImplementation group: 'com.google.code.gson', name: 'gson', version: '2.3.1'

testImplementation 'com.tngtech.archunit:archunit-junit4:0.22.0'

// https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml
testImplementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.14.0'
testImplementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.16.1'

// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.14.0'
testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.16.1'
}

jar {
Expand Down
8 changes: 8 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,11 @@ postgresql_config_version: 0
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: "thirdparty_users") string value. Specify the name of the table
# that will store the thirdparty recipe users.
# postgresql_thirdparty_users_table_name

# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: 60000) long value. Timeout in milliseconds for the idle connections
# to be closed.
# postgresql_idle_connection_timeout:

# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: null) integer value. Minimum number of idle connections to be kept
# active. If not set, minimum idle connections will be same as the connection pool size.
# postgresql_minimum_idle_connections:
8 changes: 8 additions & 0 deletions devConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,11 @@ postgresql_password: "root"
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: "thirdparty_users") string value. Specify the name of the table
# that will store the thirdparty recipe users.
# postgresql_thirdparty_users_table_name

# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: 60000) long value. Timeout in milliseconds for the idle connections
# to be closed.
# postgresql_idle_connection_timeout:

# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: null) integer value. Minimum number of idle connections to be kept
# active. If not set, minimum idle connections will be same as the connection pool size.
# postgresql_minimum_idle_connections:
12 changes: 6 additions & 6 deletions implementationDependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
"_comment": "Contains list of implementation dependencies URL for this project",
"list": [
{
"jar": "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.10/postgresql-42.2.10.jar",
"name": "PostgreSQL JDBC Driver 4.2",
"src": "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.10/postgresql-42.2.10-sources.jar"
"jar": "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.2/postgresql-42.7.2.jar",
"name": "PostgreSQL JDBC Driver 42.7.2",
"src": "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.2/postgresql-42.7.2-sources.jar"
},
{
"jar": "https://repo1.maven.org/maven2/com/zaxxer/HikariCP/3.4.1/HikariCP-3.4.1.jar",
"name": "HikariCP 3.4.1",
"src": "https://repo1.maven.org/maven2/com/zaxxer/HikariCP/3.4.1/HikariCP-3.4.1-sources.jar"
},
{
"jar": "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar",
"name": "SLF4j API 1.7.25",
"src": "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar"
"jar": "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.7/slf4j-api-2.0.7.jar",
"name": "SLF4j API 2.0.7",
"src": "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.7/slf4j-api-2.0.7-sources.jar"
}
]
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ private synchronized void initialiseHikariDataSource() throws SQLException {
}
config.setMaximumPoolSize(userConfig.getConnectionPoolSize());
config.setConnectionTimeout(5000);
if (userConfig.getMinimumIdleConnections() != null) {
config.setMinimumIdle(userConfig.getMinimumIdleConnections());
config.setIdleTimeout(userConfig.getIdleConnectionTimeout());
}
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/io/supertokens/storage/postgresql/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
import java.util.List;
import java.util.Set;

import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;

public class Start
implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage,
JWTRecipeSQLStorage, PasswordlessSQLStorage, UserMetadataSQLStorage, UserRolesSQLStorage, UserIdMappingStorage,
Expand All @@ -113,7 +115,8 @@ public class Start
// SaaS. If the core is not running in SuperTokens SaaS, this array has no effect.
private static String[] PROTECTED_DB_CONFIG = new String[]{"postgresql_connection_pool_size",
"postgresql_connection_uri", "postgresql_host", "postgresql_port", "postgresql_user", "postgresql_password",
"postgresql_database_name", "postgresql_table_schema"};
"postgresql_database_name", "postgresql_table_schema", "postgresql_idle_connection_timeout",
"postgresql_minimum_idle_connections"};
private static final Object appenderLock = new Object();
public static boolean silent = false;
private ResourceDistributor resourceDistributor = new ResourceDistributor();
Expand Down Expand Up @@ -3017,9 +3020,23 @@ public int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier ap
@Override
public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(AppIdentifier appIdentifier, long sinceTime) throws StorageQueryException {
try {
return ActiveUsersQueries.countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(this, appIdentifier, sinceTime);
return ActiveUsersQueries.countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(this,
appIdentifier, sinceTime);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@TestOnly
public int getDbActivityCount(String dbname) throws SQLException, StorageQueryException {
String QUERY = "SELECT COUNT(*) as c FROM pg_stat_activity WHERE datname = ?;";
return execute(this, QUERY, pst -> {
pst.setString(1, dbname);
}, result -> {
if (result.next()) {
return result.getInt("c");
}
return -1;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ public class PostgreSQLConfig {
@ConnectionPoolProperty
private String postgresql_connection_scheme = "postgresql";

@JsonProperty
@ConnectionPoolProperty
private long postgresql_idle_connection_timeout = 60000;

@JsonProperty
@ConnectionPoolProperty
private Integer postgresql_minimum_idle_connections = null;

@IgnoreForAnnotationCheck
boolean isValidAndNormalised = false;

Expand Down Expand Up @@ -242,6 +250,14 @@ public String getThirdPartyUsersTable() {
return postgresql_thirdparty_users_table_name;
}

public long getIdleConnectionTimeout() {
return postgresql_idle_connection_timeout;
}

public Integer getMinimumIdleConnections() {
return postgresql_minimum_idle_connections;
}

public String getThirdPartyUserToTenantTable() {
return addSchemaAndPrefixToTableName("thirdparty_user_to_tenant");
}
Expand Down Expand Up @@ -348,6 +364,19 @@ public void validateAndNormalise() throws InvalidConfigException {
"'postgresql_connection_pool_size' in the config.yaml file must be > 0");
}

if (postgresql_minimum_idle_connections != null) {
if (postgresql_minimum_idle_connections < 0) {
throw new InvalidConfigException(
"'postgresql_minimum_idle_connections' must be >= 0");
}

if (postgresql_minimum_idle_connections > postgresql_connection_pool_size) {
throw new InvalidConfigException(
"'postgresql_minimum_idle_connections' must be less than or equal to "
+ "'postgresql_connection_pool_size'");
}
}

// Normalisation
if (postgresql_connection_uri != null) {
{ // postgresql_connection_attributes
Expand Down Expand Up @@ -556,10 +585,18 @@ public String getConnectionPoolId() {
StringBuilder connectionPoolId = new StringBuilder();
for (Field field : PostgreSQLConfig.class.getDeclaredFields()) {
if (field.isAnnotationPresent(ConnectionPoolProperty.class)) {
connectionPoolId.append("|");
try {
if (field.get(this) != null) {
connectionPoolId.append(field.get(this).toString());
String fieldName = field.getName();
String fieldValue = field.get(this) != null ? field.get(this).toString() : null;
if(fieldValue == null) {
continue;
}
// To ensure a unique connectionPoolId we include the database password and use the "|db_pass|" identifier.
// This facilitates easy removal of the password from logs when necessary.
if (fieldName.equals("postgresql_password")) {
connectionPoolId.append("|db_pass|" + fieldValue + "|db_pass");
} else {
connectionPoolId.append("|" + fieldValue);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.LayoutBase;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storage.postgresql.utils.Utils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -58,7 +58,7 @@ public String doLayout(ILoggingEvent event) {
sbuf.append(event.getCallerData()[1]);
sbuf.append(" | ");

sbuf.append(event.getFormattedMessage());
sbuf.append(Utils.maskDBPassword(event.getFormattedMessage()));
sbuf.append(CoreConstants.LINE_SEPARATOR);
sbuf.append(CoreConstants.LINE_SEPARATOR);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ public class Logging extends ResourceDistributor.SingletonResource {

private Logging(Start start, String infoLogPath, String errorLogPath) {
this.infoLogger = infoLogPath.equals("null")
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Info")
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Info", LOG_LEVEL.INFO)
: createLoggerForFile(start, infoLogPath, "io.supertokens.storage.postgresql.Info");
this.errorLogger = errorLogPath.equals("null")
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Error")
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Error", LOG_LEVEL.ERROR)
: createLoggerForFile(start, errorLogPath, "io.supertokens.storage.postgresql.Error");
}

Expand Down Expand Up @@ -154,12 +154,12 @@ public static void error(Start start, String message, boolean toConsoleAsWell, E

private static void systemOut(String msg) {
if (!Start.silent) {
System.out.println(msg);
System.out.println(Utils.maskDBPassword(msg));
}
}

private static void systemErr(String err) {
System.err.println(err);
System.err.println(Utils.maskDBPassword(err));
}

public static void stopLogging(Start start) {
Expand Down Expand Up @@ -198,7 +198,7 @@ private Logger createLoggerForFile(Start start, String file, String name) {
return logger;
}

private Logger createLoggerForConsole(Start start, String name) {
private Logger createLoggerForConsole(Start start, String name, LOG_LEVEL logLevel) {
Logger logger = (Logger) LoggerFactory.getLogger(name);

if (logger.iteratorForAppenders().hasNext()) {
Expand All @@ -210,6 +210,7 @@ private Logger createLoggerForConsole(Start start, String name) {
ple.setContext(lc);
ple.start();
ConsoleAppender<ILoggingEvent> logConsoleAppender = new ConsoleAppender<>();
logConsoleAppender.setTarget(logLevel == LOG_LEVEL.ERROR ? "System.err" : "System.out");
logConsoleAppender.setEncoder(ple);
logConsoleAppender.setContext(lc);
logConsoleAppender.start();
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/io/supertokens/storage/postgresql/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils {
public static String exceptionStacktraceToString(Exception e) {
Expand Down Expand Up @@ -62,4 +64,19 @@ public static String[] getStringArrayFromJsonString(String input) {
}
return new Gson().fromJson(input, String[].class);
}

public static String maskDBPassword(String log) {
String regex = "(\\|db_pass\\|)(.*?)(\\|db_pass\\|)";

Matcher matcher = Pattern.compile(regex).matcher(log);
StringBuffer maskedLog = new StringBuffer();

while (matcher.find()) {
String maskedPassword = "*".repeat(8);
matcher.appendReplacement(maskedLog, "|" + maskedPassword + "|");
}

matcher.appendTail(maskedLog);
return maskedLog.toString();
}
}
Loading

0 comments on commit c494041

Please sign in to comment.