Skip to content

Commit

Permalink
fix: improve core config normalisation
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Jul 5, 2024
1 parent 48212a3 commit a7241ec
Show file tree
Hide file tree
Showing 17 changed files with 56 additions and 53 deletions.
23 changes: 14 additions & 9 deletions src/main/java/io/supertokens/config/CoreConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public class CoreConfig {
@ConfigDescription("Time in seconds for how long an access token is valid for. [Default: 3600 (1 hour)]")
private long access_token_validity = 3600; // in seconds

private long access_token_validity_ms = 0;

@NotConflictingInApp
@JsonProperty
@ConfigDescription("Deprecated, please see changelog. Only used in CDI<=2.18 If true, allows for immediate revocation of any access token. Keep in mind that setting this to true will result in a db query for each API call that requires authentication. (Default: false)")
Expand All @@ -73,6 +75,8 @@ public class CoreConfig {
@ConfigDescription("Time in mins for how long a refresh token is valid for. [Default: 60 * 2400 (100 days)]")
private double refresh_token_validity = 60 * 2400; // in mins

private double refresh_token_validity_ms = 0;

@IgnoreForAnnotationCheck
@JsonProperty
@ConfigDescription("Time in milliseconds for how long a password reset token / link is valid for. [Default: 3600000 (1 hour)]")
Expand Down Expand Up @@ -126,6 +130,7 @@ public class CoreConfig {
@JsonAlias({ "access_token_dynamic_signing_key_update_interval", "access_token_signing_key_update_interval" })
@ConfigDescription("Time in hours for how frequently the dynamic signing key will change. [Default: 168 (1 week)]")
private double access_token_dynamic_signing_key_update_interval = 168; // in hours
private double access_token_dynamic_signing_key_update_interval_ms = 0;

@ConfigYamlOnly
@JsonProperty
Expand Down Expand Up @@ -350,16 +355,16 @@ public int getConfigVersion() {
return core_config_version;
}

public long getAccessTokenValidity() {
return access_token_validity;
public long getAccessTokenValidityInMillis() {
return access_token_validity_ms;
}

public boolean getAccessTokenBlacklisting() {
return access_token_blacklisting;
}

public long getRefreshTokenValidity() {
return (long) (refresh_token_validity);
public long getRefreshTokenValidityInMillis() {
return (long) (refresh_token_validity_ms);
}

public long getPasswordResetTokenLifetime() {
Expand Down Expand Up @@ -405,8 +410,8 @@ public boolean getAccessTokenSigningKeyDynamic() {
return access_token_signing_key_dynamic;
}

public long getAccessTokenDynamicSigningKeyUpdateInterval() {
return (long) (access_token_dynamic_signing_key_update_interval);
public long getAccessTokenDynamicSigningKeyUpdateIntervalInMillis() {
return (long) (access_token_dynamic_signing_key_update_interval_ms);
}

public String[] getAPIKeys() {
Expand Down Expand Up @@ -746,10 +751,10 @@ void normalizeAndValidate(Main main, boolean includeConfigFilePath) throws Inval
}
}

access_token_validity = access_token_validity * 1000;
access_token_dynamic_signing_key_update_interval = access_token_dynamic_signing_key_update_interval * 3600
access_token_validity_ms = access_token_validity * 1000;
access_token_dynamic_signing_key_update_interval_ms = access_token_dynamic_signing_key_update_interval * 3600
* 1000;
refresh_token_validity = refresh_token_validity * 60 * 1000;
refresh_token_validity_ms = refresh_token_validity * 60 * 1000;

isNormalizedAndValid = true;
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/supertokens/session/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ public static SessionInformationHolder getSession(AppIdentifier appIdentifier, M
accessToken.sessionHandle,
Utils.hashSHA256(accessToken.refreshTokenHash1),
System.currentTimeMillis() +
config.getRefreshTokenValidity(), sessionInfo.useStaticKey);
config.getRefreshTokenValidityInMillis(), sessionInfo.useStaticKey);
}
sessionStorage.commitTransaction(con);

Expand Down Expand Up @@ -474,7 +474,7 @@ public static SessionInformationHolder getSession(AppIdentifier appIdentifier, M
boolean success = sessionStorage.updateSessionInfo_Transaction(accessToken.sessionHandle,
Utils.hashSHA256(accessToken.refreshTokenHash1),
System.currentTimeMillis() + Config.getConfig(tenantIdentifier, main)
.getRefreshTokenValidity(),
.getRefreshTokenValidityInMillis(),
sessionInfo.lastUpdatedSign, sessionInfo.useStaticKey);
if (!success) {
continue;
Expand Down Expand Up @@ -631,7 +631,7 @@ private static SessionInformationHolder refreshSessionHelper(
.equals(sessionInfo.refreshTokenHash2))) {
sessionStorage.updateSessionInfo_Transaction(tenantIdentifier, con, sessionHandle,
Utils.hashSHA256(Utils.hashSHA256(refreshToken)),
System.currentTimeMillis() + config.getRefreshTokenValidity(), useStaticKey);
System.currentTimeMillis() + config.getRefreshTokenValidityInMillis(), useStaticKey);

sessionStorage.commitTransaction(con);

Expand Down Expand Up @@ -730,7 +730,7 @@ private static SessionInformationHolder refreshSessionHelper(
boolean success = sessionStorage.updateSessionInfo_Transaction(sessionHandle,
Utils.hashSHA256(Utils.hashSHA256(refreshToken)),
System.currentTimeMillis() +
Config.getConfig(tenantIdentifier, main).getRefreshTokenValidity(),
Config.getConfig(tenantIdentifier, main).getRefreshTokenValidityInMillis(),
sessionInfo.lastUpdatedSign, useStaticKey);
if (!success) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public static TokenInfo createNewAccessToken(TenantIdentifier tenantIdentifier,
if (expiryTime != null) {
expires = expiryTime;
} else {
expires = now + Config.getConfig(tenantIdentifier, main).getAccessTokenValidity();
expires = now + Config.getConfig(tenantIdentifier, main).getAccessTokenValidityInMillis();
}
AccessTokenInfo accessToken = new AccessTokenInfo(sessionHandle, recipeUserId, primaryUserId, refreshTokenHash1,
expires,
Expand Down Expand Up @@ -297,7 +297,7 @@ public static TokenInfo createNewAccessTokenV1(TenantIdentifier tenantIdentifier
long now = System.currentTimeMillis();
AccessTokenInfo accessToken;

long expiryTime = now + Config.getConfig(tenantIdentifier, main).getAccessTokenValidity();
long expiryTime = now + Config.getConfig(tenantIdentifier, main).getAccessTokenValidityInMillis();
accessToken = new AccessTokenInfo(sessionHandle, userId, userId, refreshTokenHash1, expiryTime,
parentRefreshTokenHash1,
userData, antiCsrfToken, now, VERSION.V1, tenantIdentifier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public static TokenInfo createNewRefreshToken(TenantIdentifier tenantIdentifier,
String token = encryptedPayload + "." + nonce + "." + TYPE.FREE_OPTIMISED.toString();
long now = System.currentTimeMillis();
return new TokenInfo(token,
now + Config.getConfig(tenantIdentifier, main).getRefreshTokenValidity(),
now + Config.getConfig(tenantIdentifier, main).getRefreshTokenValidityInMillis(),
now);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ public synchronized void cleanExpiredAccessTokenSigningKeys() throws StorageQuer
this.appIdentifier.getAsPublicTenantIdentifier(), main);
CoreConfig config = Config.getConfig(this.appIdentifier.getAsPublicTenantIdentifier(), main);

final long signingKeyLifetime = config.getAccessTokenDynamicSigningKeyUpdateInterval()
+ SIGNING_KEY_VALIDITY_OVERLAP * config.getAccessTokenValidity();
final long signingKeyLifetime = config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis()
+ SIGNING_KEY_VALIDITY_OVERLAP * config.getAccessTokenValidityInMillis();

storage.removeAccessTokenSigningKeysBefore(appIdentifier, System.currentTimeMillis() - signingKeyLifetime);
}
Expand All @@ -222,11 +222,11 @@ public List<SigningKeys.KeyInfo> getOrCreateAndGetSigningKeys()
CoreConfig config = Config.getConfig(appIdentifier.getAsPublicTenantIdentifier(), main);

// Access token signing keys older than this are deleted (ms)
final long signingKeyLifetime = config.getAccessTokenDynamicSigningKeyUpdateInterval()
+ SIGNING_KEY_VALIDITY_OVERLAP * config.getAccessTokenValidity();
final long signingKeyLifetime = config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis()
+ SIGNING_KEY_VALIDITY_OVERLAP * config.getAccessTokenValidityInMillis();
// Keys created after this timestamp can be used to sign access tokens (ms) after the overlap period
final long keysCreatedAfterCanSign = System.currentTimeMillis()
- config.getAccessTokenDynamicSigningKeyUpdateInterval() + getDynamicSigningKeyOverlapMS();
- config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis() + getDynamicSigningKeyOverlapMS();
// Keys created after this timestamp can be used to verify access token signatures (ms)
final long keysCreatedAfterCanVerify = System.currentTimeMillis() - signingKeyLifetime;

Expand Down Expand Up @@ -359,8 +359,8 @@ public int getDynamicSigningKeyOverlapMS() throws TenantOrAppNotFoundException {
// If we didn't explicitly set it, we try to set it to a sensible default. In tests where this matters
// setDynamicSigningKeyOverlapMS should be used.
if (Main.isTesting && dynamicSigningKeyOverlapMS == 60000 &&
config.getAccessTokenDynamicSigningKeyUpdateInterval() < 60000) {
return (int) (config.getAccessTokenDynamicSigningKeyUpdateInterval() / 5);
config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis() < 60000) {
return (int) (config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis() / 5);
}
return dynamicSigningKeyOverlapMS;
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/supertokens/signingkeys/SigningKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public List<KeyInfo> getDynamicKeys()
// or if we should generate a key we can use after dynamicSigningKeyOverlapMS
System.currentTimeMillis() +
AccessTokenSigningKey.getInstance(appIdentifier, main).getDynamicSigningKeyOverlapMS() >
res.get(0).createdAtTime + config.getAccessTokenDynamicSigningKeyUpdateInterval()
res.get(0).createdAtTime + config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis()
) {
updateKeyCacheIfNotChanged(
res.stream().map(Utils::getJWTSigningKeyInfoFromKeyInfo).collect(Collectors.toList()));
Expand Down Expand Up @@ -185,7 +185,7 @@ public KeyInfo getLatestIssuedDynamicKey()
AccessTokenSigningKey.getInstance(appIdentifier, main).getDynamicSigningKeyOverlapMS() >
System.currentTimeMillis() && // the latest isn't old enough
System.currentTimeMillis() < dynamicKeys.get(1).createdAtTime +
config.getAccessTokenDynamicSigningKeyUpdateInterval() // the one before can still be used to
config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis() // the one before can still be used to
// sign
) {
return dynamicKeys.get(1);
Expand All @@ -204,7 +204,7 @@ public long getCacheDurationInSeconds()

long timeLeftForNewKeyCreation = (
latest.createdAtTime
+ config.getAccessTokenDynamicSigningKeyUpdateInterval()
+ config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis()
- AccessTokenSigningKey.getInstance(appIdentifier, main).getDynamicSigningKeyOverlapMS()
- System.currentTimeMillis()) / 1000;
return Math.max(timeLeftForNewKeyCreation, 1); // minimum 1 second of cache
Expand All @@ -215,7 +215,7 @@ public long getDynamicSigningKeyExpiryTime()
UnsupportedJWTSigningAlgorithmException {
long createdAtTime = getLatestIssuedDynamicKey().createdAtTime;
return createdAtTime + Config.getConfig(appIdentifier.getAsPublicTenantIdentifier(), main)
.getAccessTokenDynamicSigningKeyUpdateInterval();
.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis();
}

// This function is synchronized because we only want a single function to clear (and refresh) the key cache.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
.getAccessTokenBlacklisting());
result.addProperty("accessTokenValidity",
Config.getConfig(tenantIdentifier, main)
.getAccessTokenValidity());
.getAccessTokenValidityInMillis());
result.addProperty("refreshTokenValidity",
Config.getConfig(tenantIdentifier, main)
.getRefreshTokenValidity());
.getRefreshTokenValidityInMillis());
super.sendJsonResponse(200, result, resp);
} catch (StorageQueryException | StorageTransactionLogicException | TenantOrAppNotFoundException | UnsupportedJWTSigningAlgorithmException e) {
throw new ServletException(e);
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/io/supertokens/test/ConfigTest2_21.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void testThatDeprecatedConfigStillWorks() throws Exception {

CoreConfig config = Config.getConfig(process.getProcess());

long refreshValidity = config.getAccessTokenDynamicSigningKeyUpdateInterval();
long refreshValidity = config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis();

Assert.assertEquals(refreshValidity, 2 * 60 * 60 * 1000);

Expand All @@ -77,7 +77,7 @@ public void testThatNewConfigWorks() throws Exception {

CoreConfig config = Config.getConfig(process.getProcess());

long refreshValidity = config.getAccessTokenDynamicSigningKeyUpdateInterval();
long refreshValidity = config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis();

Assert.assertEquals(refreshValidity, 2 * 60 * 60 * 1000);

Expand Down
8 changes: 4 additions & 4 deletions src/test/java/io/supertokens/test/ConfigTest2_6.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void testThatCustomValuesInConfigAreLoaded() throws Exception {

CoreConfig config = Config.getConfig(process.getProcess());

long refreshValidity = config.getRefreshTokenValidity();
long refreshValidity = config.getRefreshTokenValidityInMillis();

Assert.assertEquals(refreshValidity, 60 * 1000);

Expand Down Expand Up @@ -246,10 +246,10 @@ private static void checkConfigValues(CoreConfig config, TestingProcess process)
private static void checkConfigValues(CoreConfig config, TestingProcess process, boolean telemetryDisabled) {

assertEquals("Config version did not match default", config.getConfigVersion(), 0);
assertEquals("Config access token validity did not match default", config.getAccessTokenValidity(),
assertEquals("Config access token validity did not match default", config.getAccessTokenValidityInMillis(),
3600 * 1000);
assertFalse("Config access token blacklisting did not match default", config.getAccessTokenBlacklisting());
assertEquals("Config refresh token validity did not match default", config.getRefreshTokenValidity(),
assertEquals("Config refresh token validity did not match default", config.getRefreshTokenValidityInMillis(),
60 * 2400 * 60 * (long) 1000);
assertEquals(5, config.getTotpMaxAttempts()); // 5
assertEquals(900, config.getTotpRateLimitCooldownTimeSec()); // 15 minutes
Expand All @@ -259,7 +259,7 @@ private static void checkConfigValues(CoreConfig config, TestingProcess process,
assertEquals("Config error log path did not match default", config.getErrorLogPath(process.getProcess()),
CLIOptions.get(process.getProcess()).getInstallationPath() + "logs/error.log");
assertEquals("Config access signing key interval did not match default",
config.getAccessTokenDynamicSigningKeyUpdateInterval(), 7 * 24 * 60 * 60 * 1000);
config.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis(), 7 * 24 * 60 * 60 * 1000);

assertEquals(config.getHost(process.getProcess()), "localhost");
assertEquals(config.getPort(process.getProcess()), 3567);
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/io/supertokens/test/multitenant/ConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void normalConfigContinuesToWork() throws InterruptedException, IOExcepti

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

Assert.assertEquals(Config.getConfig(process.getProcess()).getRefreshTokenValidity(),
Assert.assertEquals(Config.getConfig(process.getProcess()).getRefreshTokenValidityInMillis(),
(long) 144001 * 60 * 1000);
Assert.assertEquals(Config.getConfig(process.getProcess()).getAccessTokenSigningKeyDynamic(),
false);
Expand Down Expand Up @@ -159,7 +159,7 @@ public void mergingTenantWithBaseConfigWorks()
new PasswordlessConfig(false),
null, null, tenantConfig)}, new ArrayList<>());

Assert.assertEquals(Config.getConfig(process.getProcess()).getRefreshTokenValidity(),
Assert.assertEquals(Config.getConfig(process.getProcess()).getRefreshTokenValidityInMillis(),
(long) 144001 * 60 * 1000);
Assert.assertEquals(Config.getConfig(process.getProcess()).getPasswordResetTokenLifetime(),
3600000);
Expand All @@ -169,7 +169,7 @@ public void mergingTenantWithBaseConfigWorks()
false);

Assert.assertEquals(Config.getConfig(new TenantIdentifier("abc", null, null), process.getProcess())
.getRefreshTokenValidity(),
.getRefreshTokenValidityInMillis(),
(long) 144002 * 60 * 1000);
Assert.assertEquals(Config.getConfig(new TenantIdentifier("abc", null, null), process.getProcess())
.getPasswordResetTokenLifetime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ public void jobCleansOldKeysTest() throws Exception {
if (sessionStorage.getType() != STORAGE_TYPE.SQL) {
return;
}
long accessTokenValidity = Config.getConfig(process.getProcess()).getAccessTokenValidity();
long accessTokenValidity = Config.getConfig(process.getProcess()).getAccessTokenValidityInMillis();
long signingKeyUpdateInterval = Config.getConfig(process.getProcess())
.getAccessTokenDynamicSigningKeyUpdateInterval();
.getAccessTokenDynamicSigningKeyUpdateIntervalInMillis();

SessionSQLStorage sqlStorage = (SessionSQLStorage) sessionStorage;
sqlStorage.startTransaction(con -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public void createRefreshTokenAndLoadAfterProcessRestart()
assertSame(infoFromToken.type, TYPE.FREE_OPTIMISED);
// -5000 for some grace period for creation and checking above
assertTrue(tokenInfo.expiry > System.currentTimeMillis()
+ Config.getConfig(process.getProcess()).getRefreshTokenValidity() - 5000);
+ Config.getConfig(process.getProcess()).getRefreshTokenValidityInMillis() - 5000);

process.kill();
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STOPPED));
Expand Down
Loading

0 comments on commit a7241ec

Please sign in to comment.