diff --git a/downloader/implementationDependencies.json b/downloader/implementationDependencies.json new file mode 100644 index 000000000..f7b0897e6 --- /dev/null +++ b/downloader/implementationDependencies.json @@ -0,0 +1,5 @@ +{ +"_comment": "Contains list of implementation dependencies URL for this project. This is a generated file, don't modify the contents by hand.", +"list": [ +] +} \ No newline at end of file diff --git a/ee/implementationDependencies.json b/ee/implementationDependencies.json new file mode 100644 index 000000000..caea346a8 --- /dev/null +++ b/ee/implementationDependencies.json @@ -0,0 +1,25 @@ +{ +"_comment": "Contains list of implementation dependencies URL for this project. This is a generated file, don't modify the contents by hand.", +"list": [ + { + "jar":"https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar", + "name":"gson 2.13.1", + "src":"https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1-sources.jar" + }, + { + "jar":"https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0.jar", + "name":"error_prone_annotations 2.38.0", + "src":"https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0-sources.jar" + }, + { + "jar":"https://repo.maven.apache.org/maven2/org/jetbrains/annotations/13.0/annotations-13.0.jar", + "name":"annotations 13.0", + "src":"https://repo.maven.apache.org/maven2/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar" + }, + { + "jar":"https://repo.maven.apache.org/maven2/com/auth0/java-jwt/4.0.0/java-jwt-4.0.0.jar", + "name":"java-jwt 4.0.0", + "src":"https://repo.maven.apache.org/maven2/com/auth0/java-jwt/4.0.0/java-jwt-4.0.0-sources.jar" + } +] +} \ No newline at end of file diff --git a/src/main/java/io/supertokens/authRecipe/AuthRecipe.java b/src/main/java/io/supertokens/authRecipe/AuthRecipe.java index d3b2c6367..9c4a5fa91 100644 --- a/src/main/java/io/supertokens/authRecipe/AuthRecipe.java +++ b/src/main/java/io/supertokens/authRecipe/AuthRecipe.java @@ -27,6 +27,7 @@ import io.supertokens.pluginInterface.StorageUtils; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; import io.supertokens.pluginInterface.authRecipe.LoginMethod; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.pluginInterface.authRecipe.sqlStorage.AuthRecipeSQLStorage; import io.supertokens.pluginInterface.bulkimport.BulkImportUser; import io.supertokens.pluginInterface.bulkimport.exceptions.BulkImportBatchInsertException; @@ -286,12 +287,34 @@ private static CanLinkAccountsResult canLinkAccountsHelper(TransactionConnection tenantIds.addAll(recipeUser.tenantIds); tenantIds.addAll(primaryUser.tenantIds); - checkIfLoginMethodCanBeLinkedOnTenant(con, appIdentifier, authRecipeStorage, tenantIds, recipeUser.loginMethods[0], primaryUser); + Set emails = new HashSet<>(); + Set phoneNumbers = new HashSet<>(); + Set thirdParties = new HashSet<>(); - for (LoginMethod currLoginMethod : primaryUser.loginMethods) { - checkIfLoginMethodCanBeLinkedOnTenant(con, appIdentifier, authRecipeStorage, tenantIds, currLoginMethod, primaryUser); + for (var lm : primaryUser.loginMethods) { + if (lm.email != null) { + emails.add(lm.email); + } + if (lm.phoneNumber != null) { + phoneNumbers.add(lm.phoneNumber); + } + if (lm.thirdParty != null) { + thirdParties.add(lm.thirdParty); + } + } + for (var lm : recipeUser.loginMethods) { + if (lm.email != null) { + emails.add(lm.email); + } + if (lm.phoneNumber != null) { + phoneNumbers.add(lm.phoneNumber); + } + if (lm.thirdParty != null) { + thirdParties.add(lm.thirdParty); + } } + authRecipeStorage.checkIfLoginMethodsCanBeLinked_Transaction(con, appIdentifier, tenantIds, emails, phoneNumbers, thirdParties, primaryUser.getSupertokensUserId()); return new CanLinkAccountsResult(recipeUser.getSupertokensUserId(), primaryUser.getSupertokensUserId(), false); } @@ -707,61 +730,8 @@ private static CreatePrimaryUserResult canCreatePrimaryUserHelper(TransactionCon // this means that the user has only one login method since it's not a primary user // nor is it linked to a primary user assert (targetUser.loginMethods.length == 1); - LoginMethod loginMethod = targetUser.loginMethods[0]; - - for (String tenantId : targetUser.tenantIds) { - if (loginMethod.email != null) { - AuthRecipeUserInfo[] usersWithSameEmail = authRecipeStorage - .listPrimaryUsersByEmail_Transaction(appIdentifier, con, - loginMethod.email); - for (AuthRecipeUserInfo user : usersWithSameEmail) { - if (!user.tenantIds.contains(tenantId)) { - continue; - } - if (user.isPrimaryUser) { - throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException( - user.getSupertokensUserId(), - "This user's email is already associated with another user ID"); - } - } - } - - if (loginMethod.phoneNumber != null) { - AuthRecipeUserInfo[] usersWithSamePhoneNumber = authRecipeStorage - .listPrimaryUsersByPhoneNumber_Transaction(appIdentifier, con, - loginMethod.phoneNumber); - for (AuthRecipeUserInfo user : usersWithSamePhoneNumber) { - if (!user.tenantIds.contains(tenantId)) { - continue; - } - if (user.isPrimaryUser) { - throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException( - user.getSupertokensUserId(), - "This user's phone number is already associated with another user" + - " ID"); - } - } - } - - if (loginMethod.thirdParty != null) { - AuthRecipeUserInfo[] usersWithSameThirdParty = authRecipeStorage - .listPrimaryUsersByThirdPartyInfo_Transaction(appIdentifier, con, - loginMethod.thirdParty.id, loginMethod.thirdParty.userId); - for (AuthRecipeUserInfo userWithSameThirdParty : usersWithSameThirdParty) { - if (!userWithSameThirdParty.tenantIds.contains(tenantId)) { - continue; - } - if (userWithSameThirdParty.isPrimaryUser) { - throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException( - userWithSameThirdParty.getSupertokensUserId(), - "This user's third party login is already associated with another" + - " user ID"); - } - } - } - } - + authRecipeStorage.checkIfLoginMethodCanBecomePrimary_Transaction(appIdentifier, con, targetUser.loginMethods[0]); return new CreatePrimaryUserResult(targetUser, false); } @@ -945,7 +915,7 @@ public static CreatePrimaryUserResult createPrimaryUser(Main main, return authRecipeStorage.startTransaction(con -> { try { - CreatePrimaryUserResult result = canCreatePrimaryUserHelper(con, appIdentifier, authRecipeStorage, + CreatePrimaryUserResult result = canCreatePrimaryUserHelper(con, appIdentifier, authRecipeStorage, recipeUserId); if (result.wasAlreadyAPrimaryUser) { return result; @@ -1447,6 +1417,8 @@ private static void deleteAuthRecipeUser(TransactionConnection con, .deleteThirdPartyUser_Transaction(con, appIdentifier, userId, deleteFromUserIdToAppIdTableToo); StorageUtils.getPasswordlessStorage(storage) .deletePasswordlessUser_Transaction(con, appIdentifier, userId, deleteFromUserIdToAppIdTableToo); + StorageUtils.getAuthRecipeStorage(storage) + .deleteAccountInfoReservations_Transaction(con, appIdentifier, userId); } public static boolean deleteNonAuthRecipeUser(TenantIdentifier tenantIdentifier, Storage storage, String userId) diff --git a/src/main/java/io/supertokens/authRecipe/exception/AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException.java b/src/main/java/io/supertokens/authRecipe/exception/AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException.java deleted file mode 100644 index 7a2805f1e..000000000 --- a/src/main/java/io/supertokens/authRecipe/exception/AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023, 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.authRecipe.exception; - -public class AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException extends Exception { - public final String primaryUserId; - - public AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(String primaryUserId, String description) { - super(description); - this.primaryUserId = primaryUserId; - } -} diff --git a/src/main/java/io/supertokens/bulkimport/BulkImport.java b/src/main/java/io/supertokens/bulkimport/BulkImport.java index 05f8b6528..9d787ca3f 100644 --- a/src/main/java/io/supertokens/bulkimport/BulkImport.java +++ b/src/main/java/io/supertokens/bulkimport/BulkImport.java @@ -20,7 +20,7 @@ import io.supertokens.Main; import io.supertokens.ResourceDistributor; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; @@ -29,9 +29,9 @@ import io.supertokens.emailpassword.PasswordHashing; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; import io.supertokens.multitenancy.Multitenancy; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithEmailAlreadyExistsException; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; import io.supertokens.output.Logging; import io.supertokens.passwordless.Passwordless; import io.supertokens.pluginInterface.Storage; diff --git a/src/main/java/io/supertokens/inmemorydb/Start.java b/src/main/java/io/supertokens/inmemorydb/Start.java index 7f0273272..c25b954bb 100644 --- a/src/main/java/io/supertokens/inmemorydb/Start.java +++ b/src/main/java/io/supertokens/inmemorydb/Start.java @@ -25,6 +25,7 @@ import io.supertokens.pluginInterface.*; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; import io.supertokens.pluginInterface.authRecipe.LoginMethod; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.pluginInterface.authRecipe.sqlStorage.AuthRecipeSQLStorage; import io.supertokens.pluginInterface.bulkimport.BulkImportStorage; import io.supertokens.pluginInterface.dashboard.DashboardSearchTags; @@ -1328,6 +1329,35 @@ public boolean doesUserIdExist_Transaction(TransactionConnection con, AppIdentif } } + @Override + public void checkIfLoginMethodCanBecomePrimary_Transaction(AppIdentifier appIdentifier, TransactionConnection con, + LoginMethod loginMethod) throws + AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException, StorageQueryException { + // TODO + } + + @Override + public void checkIfLoginMethodsCanBeLinked_Transaction(TransactionConnection con, AppIdentifier appIdentifier, + Set tenantIds, Set emails, + Set phoneNumbers, + Set thirdParties, + String primaryUserId) + throws AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException, StorageQueryException { + // TODO + } + + @Override + public void addTenantIdToPrimaryUser_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, + String supertokensUserId) { + // TODO + } + + @Override + public void deleteAccountInfoReservations_Transaction(TransactionConnection con, AppIdentifier appIdentifier, + String userId) throws StorageQueryException { + // TODO + } + @Override public void updateLastActive(AppIdentifier appIdentifier, String userId) throws StorageQueryException { try { diff --git a/src/main/java/io/supertokens/multitenancy/Multitenancy.java b/src/main/java/io/supertokens/multitenancy/Multitenancy.java index e6994dd6a..81e5228ae 100644 --- a/src/main/java/io/supertokens/multitenancy/Multitenancy.java +++ b/src/main/java/io/supertokens/multitenancy/Multitenancy.java @@ -16,8 +16,19 @@ package io.supertokens.multitenancy; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.jetbrains.annotations.TestOnly; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; + import io.supertokens.Main; import io.supertokens.ResourceDistributor; import io.supertokens.authRecipe.AuthRecipe; @@ -26,13 +37,19 @@ import io.supertokens.featureflag.EE_FEATURES; import io.supertokens.featureflag.FeatureFlag; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; -import io.supertokens.multitenancy.exception.*; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; +import io.supertokens.multitenancy.exception.BadPermissionException; +import io.supertokens.multitenancy.exception.CannotDeleteNullAppIdException; +import io.supertokens.multitenancy.exception.CannotDeleteNullConnectionUriDomainException; +import io.supertokens.multitenancy.exception.CannotDeleteNullTenantException; +import io.supertokens.multitenancy.exception.CannotModifyBaseConfigException; import io.supertokens.pluginInterface.KeyValueInfo; import io.supertokens.pluginInterface.STORAGE_TYPE; import io.supertokens.pluginInterface.Storage; import io.supertokens.pluginInterface.StorageUtils; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; -import io.supertokens.pluginInterface.authRecipe.LoginMethod; import io.supertokens.pluginInterface.authRecipe.sqlStorage.AuthRecipeSQLStorage; import io.supertokens.pluginInterface.emailpassword.exceptions.DuplicateEmailException; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; @@ -53,10 +70,6 @@ import io.supertokens.storageLayer.StorageLayer; import io.supertokens.thirdparty.InvalidProviderConfigException; import io.supertokens.thirdparty.ThirdParty; -import org.jetbrains.annotations.TestOnly; - -import java.io.IOException; -import java.util.*; public class Multitenancy extends ResourceDistributor.SingletonResource { @@ -412,123 +425,23 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifier tenantIdenti AuthRecipeUserInfo userToAssociate = authRecipeStorage.getPrimaryUserById_Transaction( tenantIdentifier.toAppIdentifier(), con, userId); - if (userToAssociate != null && userToAssociate.isPrimaryUser) { - Set emails = new HashSet<>(); - Set phoneNumbers = new HashSet<>(); - Set thirdParties = new HashSet<>(); - - // Loop through all the emails, phoneNumbers and thirdPartyInfos and check for conflicts - for (LoginMethod lM : userToAssociate.loginMethods) { - if (lM.email != null) { - emails.add(lM.email); - } - if (lM.phoneNumber != null) { - phoneNumbers.add(lM.phoneNumber); - } - if (lM.thirdParty != null) { - thirdParties.add(lM.thirdParty); - } - } - - for (String email : emails) { - AuthRecipeUserInfo[] usersWithSameEmail = authRecipeStorage.listPrimaryUsersByEmail_Transaction( - tenantIdentifier.toAppIdentifier(), con, email); - for (AuthRecipeUserInfo userWithSameEmail : usersWithSameEmail) { - if (userWithSameEmail.getSupertokensUserId() - .equals(userToAssociate.getSupertokensUserId())) { - continue; // it's the same user, no need to check anything - } - if (userWithSameEmail.isPrimaryUser && userWithSameEmail.tenantIds.contains(tenantId) && - !userWithSameEmail.getSupertokensUserId().equals(userId)) { - for (LoginMethod lm1 : userWithSameEmail.loginMethods) { - if (lm1.tenantIds.contains(tenantId)) { - for (LoginMethod lm2 : userToAssociate.loginMethods) { - if (lm1.recipeId.equals(lm2.recipeId) && email.equals(lm1.email) && - lm1.email.equals(lm2.email)) { - throw new StorageTransactionLogicException( - new DuplicateEmailException()); - } - } - } - } - throw new StorageTransactionLogicException( - new AnotherPrimaryUserWithEmailAlreadyExistsException( - userWithSameEmail.getSupertokensUserId())); - } - } - } - - for (String phoneNumber : phoneNumbers) { - AuthRecipeUserInfo[] usersWithSamePhoneNumber = - authRecipeStorage.listPrimaryUsersByPhoneNumber_Transaction( - tenantIdentifier.toAppIdentifier(), con, phoneNumber); - for (AuthRecipeUserInfo userWithSamePhoneNumber : usersWithSamePhoneNumber) { - if (userWithSamePhoneNumber.getSupertokensUserId() - .equals(userToAssociate.getSupertokensUserId())) { - continue; // it's the same user, no need to check anything - } - if (userWithSamePhoneNumber.tenantIds.contains(tenantId) && - !userWithSamePhoneNumber.getSupertokensUserId().equals(userId)) { - for (LoginMethod lm1 : userWithSamePhoneNumber.loginMethods) { - if (lm1.tenantIds.contains(tenantId)) { - for (LoginMethod lm2 : userToAssociate.loginMethods) { - if (lm1.recipeId.equals(lm2.recipeId) && - phoneNumber.equals(lm1.phoneNumber) && - lm1.phoneNumber.equals(lm2.phoneNumber)) { - throw new StorageTransactionLogicException( - new DuplicatePhoneNumberException()); - } - } - } - } - throw new StorageTransactionLogicException( - new AnotherPrimaryUserWithPhoneNumberAlreadyExistsException( - userWithSamePhoneNumber.getSupertokensUserId())); - } - } - } - - for (LoginMethod.ThirdParty tp : thirdParties) { - AuthRecipeUserInfo[] usersWithSameThirdPartyInfo = - authRecipeStorage.listPrimaryUsersByThirdPartyInfo_Transaction( - tenantIdentifier.toAppIdentifier(), con, tp.id, tp.userId); - for (AuthRecipeUserInfo userWithSameThirdPartyInfo : usersWithSameThirdPartyInfo) { - if (userWithSameThirdPartyInfo.getSupertokensUserId() - .equals(userToAssociate.getSupertokensUserId())) { - continue; // it's the same user, no need to check anything - } - if (userWithSameThirdPartyInfo.tenantIds.contains(tenantId) && - !userWithSameThirdPartyInfo.getSupertokensUserId().equals(userId)) { - for (LoginMethod lm1 : userWithSameThirdPartyInfo.loginMethods) { - if (lm1.tenantIds.contains(tenantId)) { - for (LoginMethod lm2 : userToAssociate.loginMethods) { - if (lm1.recipeId.equals(lm2.recipeId) && tp.equals(lm1.thirdParty) && - lm1.thirdParty.equals(lm2.thirdParty)) { - throw new StorageTransactionLogicException( - new DuplicateThirdPartyUserException()); - } - } - } - } - - throw new StorageTransactionLogicException( - new AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException( - userWithSameThirdPartyInfo.getSupertokensUserId())); - } - } + try { + if (userToAssociate != null && userToAssociate.isPrimaryUser) { + authRecipeStorage.addTenantIdToPrimaryUser_Transaction(tenantIdentifier, con, userToAssociate.getSupertokensUserId()); } - } - // userToAssociate may be null if the user is not associated to any tenants, we can still try and - // associate it. This happens only in CDI 3.0 where we allow disassociation from all tenants - // This will not happen in CDI >= 4.0 because we will not allow disassociation from all tenants - try { + // userToAssociate may be null if the user is not associated to any tenants, we can still try and + // associate it. This happens only in CDI 3.0 where we allow disassociation from all tenants + // This will not happen in CDI >= 4.0 because we will not allow disassociation from all tenants boolean result = ((MultitenancySQLStorage) storage).addUserIdToTenant_Transaction(tenantIdentifier, con, userId); authRecipeStorage.commitTransaction(con); return result; } catch (TenantOrAppNotFoundException | UnknownUserIdException | DuplicatePhoneNumberException | - DuplicateThirdPartyUserException | DuplicateEmailException e) { + DuplicateThirdPartyUserException | DuplicateEmailException | + AnotherPrimaryUserWithPhoneNumberAlreadyExistsException | + AnotherPrimaryUserWithEmailAlreadyExistsException | + AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException e) { throw new StorageTransactionLogicException(e); } }); diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java deleted file mode 100644 index c95bfdcc3..000000000 --- a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023, 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.multitenancy.exception; - -public class AnotherPrimaryUserWithEmailAlreadyExistsException extends Exception { - public AnotherPrimaryUserWithEmailAlreadyExistsException(String primaryUserId) { - super("Another primary user with email already exists: " + primaryUserId); - } -} diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java deleted file mode 100644 index e012f9349..000000000 --- a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023, 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.multitenancy.exception; - -public class AnotherPrimaryUserWithPhoneNumberAlreadyExistsException extends Exception { - public AnotherPrimaryUserWithPhoneNumberAlreadyExistsException(String primaryUserId) { - super("Another primary user with phone number already exists: " + primaryUserId); - } -} diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java deleted file mode 100644 index d5f413cf5..000000000 --- a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023, 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.multitenancy.exception; - -public class AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException extends Exception { - public AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException(String primaryUserId) { - super("Another primary user with third party info already exists: " + primaryUserId); - } -} diff --git a/src/main/java/io/supertokens/webserver/api/accountlinking/CanCreatePrimaryUserAPI.java b/src/main/java/io/supertokens/webserver/api/accountlinking/CanCreatePrimaryUserAPI.java index a72f0d6d3..3077469e7 100644 --- a/src/main/java/io/supertokens/webserver/api/accountlinking/CanCreatePrimaryUserAPI.java +++ b/src/main/java/io/supertokens/webserver/api/accountlinking/CanCreatePrimaryUserAPI.java @@ -20,7 +20,7 @@ import io.supertokens.Main; import io.supertokens.StorageAndUserIdMapping; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; import io.supertokens.multitenancy.exception.BadPermissionException; import io.supertokens.pluginInterface.RECIPE_ID; diff --git a/src/main/java/io/supertokens/webserver/api/accountlinking/CanLinkAccountsAPI.java b/src/main/java/io/supertokens/webserver/api/accountlinking/CanLinkAccountsAPI.java index 4c5212708..90702b218 100644 --- a/src/main/java/io/supertokens/webserver/api/accountlinking/CanLinkAccountsAPI.java +++ b/src/main/java/io/supertokens/webserver/api/accountlinking/CanLinkAccountsAPI.java @@ -20,7 +20,7 @@ import io.supertokens.Main; import io.supertokens.StorageAndUserIdMapping; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.multitenancy.exception.BadPermissionException; diff --git a/src/main/java/io/supertokens/webserver/api/accountlinking/CreatePrimaryUserAPI.java b/src/main/java/io/supertokens/webserver/api/accountlinking/CreatePrimaryUserAPI.java index 1a3173dbb..98ff46f60 100644 --- a/src/main/java/io/supertokens/webserver/api/accountlinking/CreatePrimaryUserAPI.java +++ b/src/main/java/io/supertokens/webserver/api/accountlinking/CreatePrimaryUserAPI.java @@ -20,7 +20,7 @@ import io.supertokens.Main; import io.supertokens.StorageAndUserIdMapping; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; import io.supertokens.multitenancy.exception.BadPermissionException; diff --git a/src/main/java/io/supertokens/webserver/api/accountlinking/LinkAccountsAPI.java b/src/main/java/io/supertokens/webserver/api/accountlinking/LinkAccountsAPI.java index aa0d5c4fc..54b75fcd0 100644 --- a/src/main/java/io/supertokens/webserver/api/accountlinking/LinkAccountsAPI.java +++ b/src/main/java/io/supertokens/webserver/api/accountlinking/LinkAccountsAPI.java @@ -21,7 +21,7 @@ import io.supertokens.Main; import io.supertokens.StorageAndUserIdMapping; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; diff --git a/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java b/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java index 1f9d45718..b88de5e25 100644 --- a/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java +++ b/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java @@ -21,9 +21,9 @@ import io.supertokens.StorageAndUserIdMapping; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; import io.supertokens.multitenancy.Multitenancy; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithEmailAlreadyExistsException; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; -import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; import io.supertokens.pluginInterface.RECIPE_ID; import io.supertokens.pluginInterface.emailpassword.exceptions.DuplicateEmailException; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; diff --git a/src/test/java/io/supertokens/test/AuthRecipeTest.java b/src/test/java/io/supertokens/test/AuthRecipeTest.java index a9086391a..a2713b390 100644 --- a/src/test/java/io/supertokens/test/AuthRecipeTest.java +++ b/src/test/java/io/supertokens/test/AuthRecipeTest.java @@ -22,7 +22,7 @@ import io.supertokens.ResourceDistributor; import io.supertokens.authRecipe.AuthRecipe; import io.supertokens.authRecipe.UserPaginationContainer; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; diff --git a/src/test/java/io/supertokens/test/StorageTest.java b/src/test/java/io/supertokens/test/StorageTest.java index 10ff114aa..a3924ec60 100644 --- a/src/test/java/io/supertokens/test/StorageTest.java +++ b/src/test/java/io/supertokens/test/StorageTest.java @@ -69,9 +69,6 @@ public void beforeEach() { Utils.reset(); } - @Rule - public Retry retry = new Retry(3); - @Test public void transactionIsolationWithoutAnInitialRowTesting() throws Exception { String[] args = {"../"}; @@ -144,10 +141,9 @@ public void transactionIsolationWithoutAnInitialRowTesting() throws Exception { KeyValueInfo info = sqlStorage.getKeyValue_Transaction( new TenantIdentifier(null, null, null), con, key); - if (numberOfIterations.get() != 1) { - assert (info == null); - } else { - assert (info != null); + + if (info != null) { + assertTrue(numberOfIterations.get() > 0); } try { @@ -184,7 +180,7 @@ public void transactionIsolationWithoutAnInitialRowTesting() throws Exception { t2.join(); assertEquals(endValueOfCon1.get(), endValueOfCon2.get()); - assertEquals(numberOfIterations.get(), 1); + assertTrue(numberOfIterations.get() >= 1); } diff --git a/src/test/java/io/supertokens/test/accountlinking/CreatePrimaryUserTest.java b/src/test/java/io/supertokens/test/accountlinking/CreatePrimaryUserTest.java index 322d92035..cc9ecb40b 100644 --- a/src/test/java/io/supertokens/test/accountlinking/CreatePrimaryUserTest.java +++ b/src/test/java/io/supertokens/test/accountlinking/CreatePrimaryUserTest.java @@ -19,7 +19,7 @@ import com.google.gson.JsonObject; import io.supertokens.ProcessState; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; import io.supertokens.emailpassword.EmailPassword; import io.supertokens.featureflag.EE_FEATURES; diff --git a/src/test/java/io/supertokens/test/accountlinking/LinkAccountsTest.java b/src/test/java/io/supertokens/test/accountlinking/LinkAccountsTest.java index c5fdcc611..5170c2c87 100644 --- a/src/test/java/io/supertokens/test/accountlinking/LinkAccountsTest.java +++ b/src/test/java/io/supertokens/test/accountlinking/LinkAccountsTest.java @@ -20,7 +20,7 @@ import io.supertokens.ActiveUsers; import io.supertokens.ProcessState; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.emailpassword.EmailPassword; diff --git a/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java b/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java index a16d34abf..05750f372 100644 --- a/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java +++ b/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java @@ -20,7 +20,7 @@ import io.supertokens.Main; import io.supertokens.ProcessState; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.emailpassword.EmailPassword; import io.supertokens.emailpassword.exceptions.EmailChangeNotAllowedException; @@ -36,6 +36,8 @@ import io.supertokens.pluginInterface.Storage; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; import io.supertokens.pluginInterface.authRecipe.LoginMethod; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; import io.supertokens.pluginInterface.emailpassword.exceptions.DuplicateEmailException; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; import io.supertokens.pluginInterface.exceptions.InvalidConfigException; @@ -378,19 +380,19 @@ public void testVariousCases() throws Exception { t4 = new TenantIdentifier(null, "a1", "t3"); TestCase[] testCases = new TestCase[]{ - new TestCase(new TestCaseStep[]{ + /* 0 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new CreatePlessUserWithEmail(t2, "test@example.com"), new MakePrimaryUser(t1, 0), new AssociateUserToTenant(t2, 0), }), - new TestCase(new TestCaseStep[]{ + /* 1 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new CreatePlessUserWithEmail(t2, "test@example.com"), new AssociateUserToTenant(t2, 0), new MakePrimaryUser(t1, 0), }), - new TestCase(new TestCaseStep[]{ + /* 2 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new CreatePlessUserWithEmail(t2, "test@example.com"), new MakePrimaryUser(t1, 0), @@ -398,7 +400,7 @@ public void testVariousCases() throws Exception { new SignInEmailPasswordUser(t2, 0).expect(new WrongCredentialsException()) }), - new TestCase(new TestCaseStep[]{ + /* 3 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -408,7 +410,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 2), // Allowed }), - new TestCase(new TestCaseStep[]{ + /* 4 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -419,7 +421,7 @@ public void testVariousCases() throws Exception { new AnotherPrimaryUserWithEmailAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 5 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -430,7 +432,7 @@ public void testVariousCases() throws Exception { new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), }), - new TestCase(new TestCaseStep[]{ + /* 6 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -440,7 +442,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 2), // Allowed }), - new TestCase(new TestCaseStep[]{ + /* 7 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -451,7 +453,7 @@ public void testVariousCases() throws Exception { new AnotherPrimaryUserWithEmailAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 8 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -462,7 +464,7 @@ public void testVariousCases() throws Exception { new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), }), - new TestCase(new TestCaseStep[]{ + /* 9 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -472,7 +474,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 2), // Allowed }), - new TestCase(new TestCaseStep[]{ + /* 10 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -483,7 +485,7 @@ public void testVariousCases() throws Exception { new AnotherPrimaryUserWithEmailAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 11 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -494,7 +496,7 @@ public void testVariousCases() throws Exception { new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), }), - new TestCase(new TestCaseStep[]{ + /* 12 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreatePlessUserWithEmail(t2, "test2@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -503,7 +505,7 @@ public void testVariousCases() throws Exception { new UpdatePlessUserEmail(t1, 0, "test2@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 13 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreatePlessUserWithEmail(t1, "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -514,7 +516,7 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 14 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreatePlessUserWithEmail(t1, "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -525,7 +527,7 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 15 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithPhone(t1, "+1000001"), new CreatePlessUserWithPhone(t1, "+1000003"), new CreatePlessUserWithPhone(t2, "+1000002"), @@ -535,7 +537,7 @@ public void testVariousCases() throws Exception { new UpdatePlessUserPhone(t1, 0, "+1000003").expect(new PhoneNumberChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 16 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithPhone(t1, "+1000001"), new CreatePlessUserWithPhone(t1, "+1000003"), new CreatePlessUserWithPhone(t2, "+1000002"), @@ -545,7 +547,7 @@ public void testVariousCases() throws Exception { new UpdatePlessUserPhone(t1, 1, "+1000001").expect(new PhoneNumberChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 17 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -556,7 +558,7 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 18 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -567,7 +569,7 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 19 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -577,7 +579,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 2), // Allowed }), - new TestCase(new TestCaseStep[]{ + /* 20 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -588,7 +590,7 @@ public void testVariousCases() throws Exception { new AnotherPrimaryUserWithEmailAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 21 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -599,7 +601,7 @@ public void testVariousCases() throws Exception { new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), }), - new TestCase(new TestCaseStep[]{ + /* 22 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -609,7 +611,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 2), // Allowed }), - new TestCase(new TestCaseStep[]{ + /* 23 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -620,7 +622,7 @@ public void testVariousCases() throws Exception { new AnotherPrimaryUserWithEmailAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 24 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -631,7 +633,7 @@ public void testVariousCases() throws Exception { new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), }), - new TestCase(new TestCaseStep[]{ + /* 25 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid2", "test2@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -640,7 +642,7 @@ public void testVariousCases() throws Exception { new CreateThirdPartyUser(t1, "google", "googleid1", "test2@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 26 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), new CreateThirdPartyUser(t1, "google", "googleid3", "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -651,7 +653,7 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 27 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), new CreateThirdPartyUser(t1, "google", "googleid3", "test3@example.com"), new CreateEmailPasswordUser(t2, "test2@example.com"), @@ -662,30 +664,30 @@ public void testVariousCases() throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 28 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithPhone(t1, "+1000001"), new CreatePlessUserWithPhone(t2, "+1000002"), new CreatePlessUserWithPhone(t3, "+1000001"), new MakePrimaryUser(t1, 0), new LinkAccounts(t1, 0, 1), new MakePrimaryUser(t3, 2), - new AssociateUserToTenant(t1, 2).expect(new DuplicatePhoneNumberException()), + new AssociateUserToTenant(t1, 2).expect(new AnotherPrimaryUserWithPhoneNumberAlreadyExistsException("")), new AssociateUserToTenant(t2, 2).expect( new AnotherPrimaryUserWithPhoneNumberAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 29 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid2", "test2@example.com"), new CreateThirdPartyUser(t3, "google", "googleid1", "test3@example.com"), new MakePrimaryUser(t1, 0), new LinkAccounts(t1, 0, 1), new MakePrimaryUser(t3, 2), - new AssociateUserToTenant(t1, 2).expect(new DuplicateThirdPartyUserException()), + new AssociateUserToTenant(t1, 2).expect(new io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException("")), new AssociateUserToTenant(t2, 2).expect( - new AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException("")), + new io.supertokens.pluginInterface.authRecipe.exceptions.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException("")), }), - new TestCase(new TestCaseStep[]{ + /* 30 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), new CreateThirdPartyUser(t2, "google", "googleid2", "test2@example.com"), new CreateThirdPartyUser(t1, "google", "googleid3", "test3@example.com"), @@ -697,7 +699,7 @@ public void testVariousCases() throws Exception { new CreateThirdPartyUser(t1, "google", "googleid3", "test1@example.com").expect( new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 31 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -706,7 +708,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 0).expect(new UnknownUserIdException()), }), - new TestCase(new TestCaseStep[]{ + /* 32 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test@example.com"), new CreatePlessUserWithEmail(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -715,7 +717,7 @@ public void testVariousCases() throws Exception { new AssociateUserToTenant(t2, 0).expect(new UnknownUserIdException()), }), - new TestCase(new TestCaseStep[]{ + /* 33 */ new TestCase(new TestCaseStep[]{ new CreateThirdPartyUser(t1, "google", "googleid1", "test@example.com"), new CreateThirdPartyUser(t1, "google", "googleid2", "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -723,7 +725,7 @@ public void testVariousCases() throws Exception { new UnlinkAccount(t1, 0), new AssociateUserToTenant(t2, 0).expect(new UnknownUserIdException()), }), - new TestCase(new TestCaseStep[]{ + /* 34 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -743,7 +745,7 @@ public void execute(Main main) throws Exception { } }), - new TestCase(new TestCaseStep[]{ + /* 35 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new DisassociateUserFromTenant(t1, 0), new CreateEmailPasswordUser(t1, "test@example.com"), @@ -756,7 +758,7 @@ public void execute(Main main) throws Exception { new RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException(null, "")), }), - new TestCase(new TestCaseStep[]{ + /* 36 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test@example.com"), new DisassociateUserFromTenant(t1, 0), new CreateEmailPasswordUser(t1, "test@example.com"), @@ -767,7 +769,7 @@ public void execute(Main main) throws Exception { new AssociateUserToTenant(t1, 1).expect(new DuplicateEmailException()), new AssociateUserToTenant(t2, 1), }), - new TestCase(new TestCaseStep[]{ + /* 37 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -792,33 +794,33 @@ public void execute(Main main) throws Exception { } }), - new TestCase(new TestCaseStep[]{ + /* 38 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), new UpdatePlessUserEmail(t1, 1, "test1@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 39 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), new UpdateEmailPasswordUserEmail(t1, 1, "test1@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 40 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t1, "test2@example.com"), new MakePrimaryUser(t1, 1), new UpdatePlessUserEmail(t1, 1, "test1@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 41 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 1), new UpdateEmailPasswordUserEmail(t1, 1, "test1@example.com"), }), - new TestCase(new TestCaseStep[]{ + /* 42 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreatePlessUserWithEmail(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -826,7 +828,7 @@ public void execute(Main main) throws Exception { new UpdatePlessUserEmail(t1, 1, "test1@example.com").expect( new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 43 */ new TestCase(new TestCaseStep[]{ new CreatePlessUserWithEmail(t1, "test1@example.com"), new CreateEmailPasswordUser(t1, "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -835,19 +837,19 @@ public void execute(Main main) throws Exception { new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 44 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t1, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 0), new CreateThirdPartyUser(t1, "google", "googleid", "test2@example.com"), // allowed }), - new TestCase(new TestCaseStep[]{ + /* 45 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t1, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 1), new CreateThirdPartyUser(t1, "google", "googleid", "test2@example.com"), // allowed }), - new TestCase(new TestCaseStep[]{ + /* 46 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateThirdPartyUser(t1, "google", "googleid", "test2@example.com"), new MakePrimaryUser(t1, 0), @@ -855,7 +857,7 @@ public void execute(Main main) throws Exception { new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com").expect( new EmailChangeNotAllowedException()), }), - new TestCase(new TestCaseStep[]{ + /* 47 */ new TestCase(new TestCaseStep[]{ new CreateEmailPasswordUser(t1, "test1@example.com"), new CreateEmailPasswordUser(t2, "test3@example.com"), new MakePrimaryUser(t1, 0), diff --git a/src/test/java/io/supertokens/test/httpRequest/HttpRequestForTesting.java b/src/test/java/io/supertokens/test/httpRequest/HttpRequestForTesting.java index aaf12424e..d4976d64c 100644 --- a/src/test/java/io/supertokens/test/httpRequest/HttpRequestForTesting.java +++ b/src/test/java/io/supertokens/test/httpRequest/HttpRequestForTesting.java @@ -296,7 +296,7 @@ public static T sendJsonRequest(Main main, String requestID, String url, Jso con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod(method); con.setConnectTimeout(connectionTimeoutMS); - con.setReadTimeout(readTimeoutMS + 1000); + con.setReadTimeout(readTimeoutMS * 3); con.setInstanceFollowRedirects(followRedirects); con.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); if (version != null) { diff --git a/src/test/java/io/supertokens/test/multitenant/TestAppData.java b/src/test/java/io/supertokens/test/multitenant/TestAppData.java index 591cd9f48..5d8f14adf 100644 --- a/src/test/java/io/supertokens/test/multitenant/TestAppData.java +++ b/src/test/java/io/supertokens/test/multitenant/TestAppData.java @@ -24,6 +24,7 @@ import javax.crypto.spec.SecretKeySpec; +import io.supertokens.authRecipe.AuthRecipe; import org.apache.commons.codec.binary.Base32; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; @@ -154,6 +155,7 @@ null, null, new JsonObject() "password"); EmailPassword.generatePasswordResetTokenBeforeCdi4_0(app, appStorage, process.getProcess(), epUser.getSupertokensUserId()); + AuthRecipe.createPrimaryUser(process.getProcess(), app.toAppIdentifier(), appStorage, epUser.getSupertokensUserId()); ThirdParty.SignInUpResponse tpUser = ThirdParty.signInUp(app, appStorage, process.getProcess(), "google", "googleid", "test@example.com"); diff --git a/src/test/java/io/supertokens/test/userMetadata/UserMetadataTest.java b/src/test/java/io/supertokens/test/userMetadata/UserMetadataTest.java index 9eb5c0b30..fd41af978 100644 --- a/src/test/java/io/supertokens/test/userMetadata/UserMetadataTest.java +++ b/src/test/java/io/supertokens/test/userMetadata/UserMetadataTest.java @@ -193,134 +193,110 @@ public void testUserMetadataEmptyRowLocking() throws Exception { return; } - String userId = "userId"; - - JsonObject expected = new JsonObject(); - JsonObject update1 = new JsonObject(); - update1.addProperty("a", 1); - expected.addProperty("a", 1); + // Repeat concurrent test 100 times + for (int idx = 0; idx < 100; idx++) { + String userId = "userId" + idx; - JsonObject update2 = new JsonObject(); - update2.addProperty("b", 2); - expected.addProperty("b", 2); + JsonObject expected = new JsonObject(); + JsonObject update1 = new JsonObject(); + update1.addProperty("a", 1); + expected.addProperty("a", 1); - UserMetadataSQLStorage sqlStorage = (UserMetadataSQLStorage) StorageLayer.getStorage(process.getProcess()); + JsonObject update2 = new JsonObject(); + update2.addProperty("b", 2); + expected.addProperty("b", 2); - AtomicReference t1State = new AtomicReference<>("init"); - AtomicReference t2State = new AtomicReference<>("init"); - final Object syncObject = new Object(); + UserMetadataSQLStorage sqlStorage = (UserMetadataSQLStorage) StorageLayer.getStorage(process.getProcess()); - AtomicInteger tryCount1 = new AtomicInteger(0); - AtomicInteger tryCount2 = new AtomicInteger(0); - AtomicBoolean success1 = new AtomicBoolean(false); - AtomicBoolean success2 = new AtomicBoolean(false); + AtomicReference t1State = new AtomicReference<>("init"); + AtomicReference t2State = new AtomicReference<>("init"); + final Object syncObject = new Object(); - AppIdentifier appIdentifier = process.getAppForTesting().toAppIdentifier(); + AtomicInteger tryCount1 = new AtomicInteger(0); + AtomicInteger tryCount2 = new AtomicInteger(0); + AtomicBoolean success1 = new AtomicBoolean(false); + AtomicBoolean success2 = new AtomicBoolean(false); - Runnable r1 = () -> { - try { - sqlStorage.startTransaction(con -> { - tryCount1.incrementAndGet(); - JsonObject originalMetadata = sqlStorage.getUserMetadata_Transaction(appIdentifier, con, userId); + AppIdentifier appIdentifier = process.getAppForTesting().toAppIdentifier(); - synchronized (syncObject) { - t1State.set("read"); - syncObject.notifyAll(); - } + Runnable r1 = () -> { + try { + sqlStorage.startTransaction(con -> { + tryCount1.incrementAndGet(); - synchronized (syncObject) { - while (!t2State.get().equals("read")) { - try { - syncObject.wait(); - } catch (InterruptedException e) { - } - } - } + JsonObject originalMetadata = sqlStorage.getUserMetadata_Transaction(appIdentifier, con, userId); - JsonObject updatedMetadata = originalMetadata == null ? new JsonObject() : originalMetadata; - MetadataUtils.shallowMergeMetadataUpdate(updatedMetadata, update1); + JsonObject updatedMetadata = originalMetadata == null ? new JsonObject() : originalMetadata; + MetadataUtils.shallowMergeMetadataUpdate(updatedMetadata, update1); - try { - sqlStorage.setUserMetadata_Transaction(appIdentifier, con, userId, - updatedMetadata); - } catch (TenantOrAppNotFoundException e) { - throw new StorageTransactionLogicException(e); + try { + sqlStorage.setUserMetadata_Transaction(appIdentifier, con, userId, + updatedMetadata); + } catch (TenantOrAppNotFoundException e) { + throw new StorageTransactionLogicException(e); + } + sqlStorage.commitTransaction(con); + success1.set(true); // it should come here because we will try three times. + return null; + }); + } catch (StorageTransactionLogicException e) { + if (e.actualException instanceof TenantOrAppNotFoundException) { + throw new IllegalStateException(e.actualException); } - sqlStorage.commitTransaction(con); - success1.set(true); // it should come here because we will try three times. - return null; - }); - } catch (StorageTransactionLogicException e) { - if (e.actualException instanceof TenantOrAppNotFoundException) { - throw new IllegalStateException(e.actualException); + } catch (Exception ignored) { } - } catch (Exception ignored) { - } - }; + }; - Runnable r2 = () -> { - try { - sqlStorage.startTransaction(con -> { - tryCount2.incrementAndGet(); + Runnable r2 = () -> { + try { + sqlStorage.startTransaction(con -> { + tryCount2.incrementAndGet(); - JsonObject originalMetadata = sqlStorage.getUserMetadata_Transaction(appIdentifier, con, userId); + JsonObject originalMetadata = sqlStorage.getUserMetadata_Transaction(appIdentifier, con, userId); - synchronized (syncObject) { - t2State.set("read"); - syncObject.notifyAll(); - } + JsonObject updatedMetadata = originalMetadata == null ? new JsonObject() : originalMetadata; + MetadataUtils.shallowMergeMetadataUpdate(updatedMetadata, update2); - synchronized (syncObject) { - while (!t1State.get().equals("read")) { - try { - syncObject.wait(); - } catch (InterruptedException e) { - } + try { + sqlStorage.setUserMetadata_Transaction(appIdentifier, con, userId, + updatedMetadata); + } catch (TenantOrAppNotFoundException e) { + throw new StorageTransactionLogicException(e); } - } - - JsonObject updatedMetadata = originalMetadata == null ? new JsonObject() : originalMetadata; - MetadataUtils.shallowMergeMetadataUpdate(updatedMetadata, update2); - try { - sqlStorage.setUserMetadata_Transaction(appIdentifier, con, userId, - updatedMetadata); - } catch (TenantOrAppNotFoundException e) { - throw new StorageTransactionLogicException(e); + sqlStorage.commitTransaction(con); + success2.set(true); // it should come here because we will try three times. + return null; + }); + } catch (StorageTransactionLogicException e) { + if (e.actualException instanceof TenantOrAppNotFoundException) { + throw new IllegalStateException(e.actualException); } - - sqlStorage.commitTransaction(con); - success2.set(true); // it should come here because we will try three times. - return null; - }); - } catch (StorageTransactionLogicException e) { - if (e.actualException instanceof TenantOrAppNotFoundException) { - throw new IllegalStateException(e.actualException); + } catch (Exception ignored) { } - } catch (Exception ignored) { - } - }; - Thread t1 = new Thread(r1); - Thread t2 = new Thread(r2); + }; + Thread t1 = new Thread(r1); + Thread t2 = new Thread(r2); - t1.start(); - t2.start(); + t1.start(); + t2.start(); - t1.join(5000); - t2.join(5000); + t1.join(5000); + t2.join(5000); - // The empty row did not lock, so we check if the system found a deadlock and that we could resolve it. + // The empty row did not lock, so we check if the system found a deadlock and that we could resolve it. - // Both succeeds in the end - assertTrue(success1.get()); - assertTrue(success2.get()); + // Both succeeds in the end + assertTrue(success1.get()); + assertTrue(success2.get()); - // One of them had to be retried (not deterministic which) - assertEquals(3, tryCount1.get() + tryCount2.get()); - // assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); + // One of them had to be retried (not deterministic which) + assertTrue(3 >= tryCount1.get() + tryCount2.get()); + // assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); - // The end result is as expected - assertEquals(expected, sqlStorage.getUserMetadata(appIdentifier, userId)); + // The end result is as expected + assertEquals(expected, sqlStorage.getUserMetadata(appIdentifier, userId)); + } process.kill(); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); diff --git a/src/test/java/io/supertokens/test/webauthn/Utils.java b/src/test/java/io/supertokens/test/webauthn/Utils.java index 66f2a2a6d..107676342 100644 --- a/src/test/java/io/supertokens/test/webauthn/Utils.java +++ b/src/test/java/io/supertokens/test/webauthn/Utils.java @@ -29,7 +29,7 @@ import com.webauthn4j.util.Base64UrlUtil; import io.supertokens.Main; import io.supertokens.authRecipe.AuthRecipe; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException; diff --git a/src/test/java/io/supertokens/test/webauthn/WebauthNAccountLinkingFlowTest.java b/src/test/java/io/supertokens/test/webauthn/WebauthNAccountLinkingFlowTest.java index d329116d0..100b37cb0 100644 --- a/src/test/java/io/supertokens/test/webauthn/WebauthNAccountLinkingFlowTest.java +++ b/src/test/java/io/supertokens/test/webauthn/WebauthNAccountLinkingFlowTest.java @@ -18,7 +18,7 @@ import com.google.gson.JsonObject; import io.supertokens.ProcessState; -import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; +import io.supertokens.pluginInterface.authRecipe.exceptions.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException; import io.supertokens.featureflag.EE_FEATURES; import io.supertokens.featureflag.FeatureFlagTestContent;