Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resource reloading #673

Merged
merged 8 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void updateEnabledFeaturesValueReadFromDbTime(long newTime) {
public void constructor(Main main, AppIdentifier appIdentifier) {
this.main = main;
this.appIdentifier = appIdentifier;
Cronjobs.addCronjob(main, EELicenseCheck.getInstance(main, this.appIdentifier.getAsPublicTenantIdentifier()));
Cronjobs.addCronjob(main, EELicenseCheck.getNewInstance(main, this.appIdentifier.getAsPublicTenantIdentifier()));
rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved
try {
this.syncFeatureFlagWithLicenseKey();
} catch (HttpResponseException | IOException e) {
Expand Down
15 changes: 10 additions & 5 deletions ee/src/main/java/io/supertokens/ee/cronjobs/EELicenseCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.supertokens.Main;
import io.supertokens.cronjobs.CronTask;
import io.supertokens.cronjobs.CronTaskTest;
import io.supertokens.cronjobs.Cronjobs;
import io.supertokens.ee.EEFeatureFlag;
import io.supertokens.featureflag.FeatureFlag;
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
Expand All @@ -16,15 +17,19 @@ private EELicenseCheck(Main main, TenantIdentifier targetTenant) {
super("EELicenseCheck", main, targetTenant);
}
rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved

public static EELicenseCheck getInstance(Main main, TenantIdentifier tenantIdentifier) {
public static EELicenseCheck getNewInstance(Main main, TenantIdentifier tenantIdentifier) {
try {
return (EELicenseCheck) main.getResourceDistributor()
EELicenseCheck existingCronTask = (EELicenseCheck) main.getResourceDistributor()
.getResource(tenantIdentifier, RESOURCE_KEY);

Cronjobs.removeCronjob(main, existingCronTask);
main.getResourceDistributor().removeResource(tenantIdentifier, RESOURCE_KEY);
} catch (TenantOrAppNotFoundException e) {
return (EELicenseCheck) main.getResourceDistributor()
.setResource(tenantIdentifier, RESOURCE_KEY,
new EELicenseCheck(main, tenantIdentifier));
// ignore
}
return (EELicenseCheck) main.getResourceDistributor()
.setResource(tenantIdentifier, RESOURCE_KEY,
new EELicenseCheck(main, tenantIdentifier));
}

@Override
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/supertokens/ResourceDistributor.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,27 @@ public synchronized SingletonResource setResource(TenantIdentifier tenantIdentif
return resource;
}

public synchronized SingletonResource removeResource(TenantIdentifier tenantIdentifier,
@Nonnull String key) {
SingletonResource singletonResource = resources.get(new KeyClass(tenantIdentifier, key));
if (singletonResource == null) {
return null;
}
resources.remove(new KeyClass(tenantIdentifier, key), singletonResource);
rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved
return singletonResource;
}

public synchronized SingletonResource setResource(AppIdentifier appIdentifier,
@Nonnull String key,
SingletonResource resource) {
return setResource(appIdentifier.getAsPublicTenantIdentifier(), key, resource);
}

public synchronized SingletonResource removeResource(AppIdentifier appIdentifier,
@Nonnull String key) {
return removeResource(appIdentifier.getAsPublicTenantIdentifier(), key);
}

public synchronized void clearAllResourcesWithResourceKey(String inputKey) {
List<KeyClass> toRemove = new ArrayList<>();
resources.forEach((key, value) -> {
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/io/supertokens/emailpassword/EmailPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ public static long getPasswordResetTokenLifetimeForTests(Main main) {

private static long getPasswordResetTokenLifetime(TenantIdentifier tenantIdentifier, Main main)
throws TenantOrAppNotFoundException {
if (Main.isTesting) {
return EmailPasswordTest.getInstance(main).getPasswordResetTokenLifetime();
}
return Config.getConfig(tenantIdentifier, main).getPasswordResetTokenLifetime();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ public static long getEmailVerificationTokenLifetimeForTests(Main main) {

private static long getEmailVerificationTokenLifetime(TenantIdentifier tenantIdentifier, Main main)
throws TenantOrAppNotFoundException {
if (Main.isTesting) {
return EmailVerificationTest.getInstance(main).getEmailVerificationTokenLifetime();
}
return Config.getConfig(tenantIdentifier, main).getEmailVerificationTokenLifetime();
}

Expand Down
22 changes: 4 additions & 18 deletions src/main/java/io/supertokens/featureflag/FeatureFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,27 +125,13 @@ public static void initForBaseTenant(Main main, String eeFolderPath) throws Malf
public static void loadForAllTenants(Main main, List<AppIdentifier> apps) {
try {
main.getResourceDistributor().withResourceDistributorLock(() -> {
rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved
Map<ResourceDistributor.KeyClass, ResourceDistributor.SingletonResource> existingResources =
main.getResourceDistributor()
.getAllResourcesWithResourceKey(RESOURCE_KEY);
main.getResourceDistributor().clearAllResourcesWithResourceKey(RESOURCE_KEY);
for (AppIdentifier app : apps) {
ResourceDistributor.SingletonResource resource = existingResources.get(
new ResourceDistributor.KeyClass(
main.getResourceDistributor()
.setResource(
app,
RESOURCE_KEY));
if (resource != null) {
main.getResourceDistributor()
.setResource(app,
RESOURCE_KEY,
resource);
} else {
main.getResourceDistributor()
.setResource(
app,
RESOURCE_KEY,
new FeatureFlag(main, app));
}
RESOURCE_KEY,
new FeatureFlag(main, app));
}
});
} catch (ResourceDistributor.FuncException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,14 @@ public static RefreshTokenKey getInstance(Main main) {
public static void loadForAllTenants(Main main, List<AppIdentifier> apps) {
try {
main.getResourceDistributor().withResourceDistributorLock(() -> {
Map<ResourceDistributor.KeyClass, ResourceDistributor.SingletonResource> existingResources =
main.getResourceDistributor()
.getAllResourcesWithResourceKey(RESOURCE_KEY);
main.getResourceDistributor().clearAllResourcesWithResourceKey(RESOURCE_KEY);
for (AppIdentifier app : apps) {
ResourceDistributor.SingletonResource resource = existingResources.get(
new ResourceDistributor.KeyClass(app, RESOURCE_KEY));
if (resource != null) {
main.getResourceDistributor().setResource(app, RESOURCE_KEY,
resource);
} else {
try {
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY,
new RefreshTokenKey(app, main));
} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
try {
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY,
new RefreshTokenKey(app, main));
} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,30 +92,16 @@ public static AccessTokenSigningKey getInstance(Main main) {
public static void loadForAllTenants(Main main, List<AppIdentifier> apps) {
try {
main.getResourceDistributor().withResourceDistributorLock(() -> {
Map<ResourceDistributor.KeyClass, ResourceDistributor.SingletonResource> existingResources =
main.getResourceDistributor()
.getAllResourcesWithResourceKey(RESOURCE_KEY);
main.getResourceDistributor().clearAllResourcesWithResourceKey(RESOURCE_KEY);
for (AppIdentifier app : apps) {
ResourceDistributor.SingletonResource resource = existingResources.get(
new ResourceDistributor.KeyClass(
app,
RESOURCE_KEY));
if (resource != null) {
try {
main.getResourceDistributor()
.setResource(app,
.setResource(
app,
RESOURCE_KEY,
resource);
} else {
try {
main.getResourceDistributor()
.setResource(
app,
RESOURCE_KEY,
new AccessTokenSigningKey(app, main));
} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
new AccessTokenSigningKey(app, main));
} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
}
});
Expand Down
24 changes: 7 additions & 17 deletions src/main/java/io/supertokens/signingkeys/JWTSigningKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,17 @@ public static void loadForAllTenants(Main main, List<AppIdentifier> apps)
try {
main.getResourceDistributor().withResourceDistributorLock(() -> {
try {
Map<ResourceDistributor.KeyClass, ResourceDistributor.SingletonResource> existingResources =
main.getResourceDistributor()
.getAllResourcesWithResourceKey(RESOURCE_KEY);
main.getResourceDistributor().clearAllResourcesWithResourceKey(RESOURCE_KEY);
for (AppIdentifier app : apps) {
ResourceDistributor.SingletonResource resource = existingResources.get(
new ResourceDistributor.KeyClass(app, RESOURCE_KEY));
if (resource != null) {
main.getResourceDistributor().setResource(app, RESOURCE_KEY,
resource);
} else {
try {
JWTSigningKey jwtSigningKey = new JWTSigningKey(app, main);
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY, jwtSigningKey);
try {
JWTSigningKey jwtSigningKey = new JWTSigningKey(app, main);
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY, jwtSigningKey);

jwtSigningKey.generateKeysForSupportedAlgos(main);
jwtSigningKey.generateKeysForSupportedAlgos(main);

} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
} catch (TenantOrAppNotFoundException e) {
throw new IllegalStateException(e);
}
}
} catch (UnsupportedJWTSigningAlgorithmException e) {
Expand Down
16 changes: 3 additions & 13 deletions src/main/java/io/supertokens/signingkeys/SigningKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,11 @@ public static SigningKeys getInstance(Main main) {
public static void loadForAllTenants(Main main, List<AppIdentifier> apps) {
try {
main.getResourceDistributor().withResourceDistributorLock(() -> {
Map<ResourceDistributor.KeyClass, ResourceDistributor.SingletonResource> existingResources =
main.getResourceDistributor()
.getAllResourcesWithResourceKey(RESOURCE_KEY);
main.getResourceDistributor().clearAllResourcesWithResourceKey(RESOURCE_KEY);
for (AppIdentifier app : apps) {
ResourceDistributor.SingletonResource resource = existingResources.get(
new ResourceDistributor.KeyClass(app, RESOURCE_KEY));
if (resource != null) {
main.getResourceDistributor().setResource(app, RESOURCE_KEY,
resource);
} else {
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY,
new SigningKeys(app, main));
}
main.getResourceDistributor()
.setResource(app, RESOURCE_KEY,
new SigningKeys(app, main));
}
});
} catch (ResourceDistributor.FuncException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public void checkingCronJob() throws Exception {

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
CronTaskTest.getInstance(process.getProcess())
.setIntervalInSeconds(DeleteExpiredPasswordResetTokens.RESOURCE_KEY, 2);
.setIntervalInSeconds(DeleteExpiredPasswordResetTokens.RESOURCE_KEY, 1);
Utils.setValueInConfig("password_reset_token_lifetime", "4000");
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
Expand All @@ -68,27 +69,26 @@ public void checkingCronJob() throws Exception {
String tok = EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);
String tok2 = EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);

io.supertokens.emailpassword.EmailPasswordTest.getInstance(process.getProcess())
.setPasswordResetTokenLifetime(10);
Thread.sleep(2000);

EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);
EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);
String tok3 = EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);
String tok4 = EmailPassword.generatePasswordResetToken(process.getProcess(), user.id);

assert (((EmailPasswordSQLStorage) StorageLayer.getStorage(process.getProcess()))
.getAllPasswordResetTokenInfoForUser(new AppIdentifier(null, null), user.id).length == 4);

Thread.sleep(3000);
Thread.sleep(3500);

PasswordResetTokenInfo[] tokens = ((EmailPasswordSQLStorage) StorageLayer.getStorage(process.getProcess()))
.getAllPasswordResetTokenInfoForUser(new AppIdentifier(null, null), user.id);

assert (tokens.length == 2);

assert (!tokens[0].token.equals(tokens[1].token));
assert (tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok))
|| tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok2)));
assert (tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok))
|| tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok2)));
assert (tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok3))
|| tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok4)));
assert (tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok3))
|| tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok4)));

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ public void passwordResetTokenExpiredCheck() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
io.supertokens.emailpassword.EmailPasswordTest.getInstance(process.getProcess())
.setPasswordResetTokenLifetime(10);
Utils.setValueInConfig("password_reset_token_lifetime", "10");
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ public void checkingCronJob() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
Utils.setValueInConfig("email_verification_token_lifetime", "4000");
CronTaskTest.getInstance(process.getProcess())
.setIntervalInSeconds(DeleteExpiredEmailVerificationTokens.RESOURCE_KEY, 2);
.setIntervalInSeconds(DeleteExpiredEmailVerificationTokens.RESOURCE_KEY, 1);
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
Expand All @@ -70,28 +71,27 @@ public void checkingCronJob() throws Exception {
String tok = EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);
String tok2 = EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);

io.supertokens.emailverification.EmailVerificationTest.getInstance(process.getProcess())
.setEmailVerificationTokenLifetime(10);
Thread.sleep(2000);

EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);
EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);
String tok3 = EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);
String tok4 = EmailVerification.generateEmailVerificationToken(process.getProcess(), user.id, user.email);

assert (((EmailVerificationSQLStorage) StorageLayer.getStorage(process.getProcess()))
.getAllEmailVerificationTokenInfoForUser(new TenantIdentifier(null, null, null), user.id, user.email).length ==
4);

Thread.sleep(3000);
Thread.sleep(3500);

EmailVerificationTokenInfo[] tokens = ((EmailVerificationSQLStorage) StorageLayer.getStorage(process.getProcess()))
.getAllEmailVerificationTokenInfoForUser(new TenantIdentifier(null, null, null), user.id, user.email);

assert (tokens.length == 2);

assert (!tokens[0].token.equals(tokens[1].token));
assert (tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok))
|| tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok2)));
assert (tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok))
|| tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok2)));
assert (tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok3))
|| tokens[0].token.equals(io.supertokens.utils.Utils.hashSHA256(tok4)));
assert (tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok3))
|| tokens[1].token.equals(io.supertokens.utils.Utils.hashSHA256(tok4)));

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