Skip to content

Commit

Permalink
fix: multitenancy related changes
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Aug 30, 2023
1 parent 2031f5d commit e5ad501
Show file tree
Hide file tree
Showing 7 changed files with 528 additions and 79 deletions.
61 changes: 41 additions & 20 deletions src/main/java/io/supertokens/authRecipe/AuthRecipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ private static CanLinkAccountsResult canLinkAccountsHelper(TransactionConnection
assert (recipeUser.loginMethods.length == 1);
LoginMethod recipeUserIdLM = recipeUser.loginMethods[0];

Set<String> tenantIds = recipeUser.tenantIds;
Set<String> tenantIds = new HashSet<>();
tenantIds.addAll(recipeUser.tenantIds);
tenantIds.addAll(primaryUser.tenantIds);

// we loop through the union of both the user's tenantIds and check that the criteria for
Expand All @@ -267,9 +268,12 @@ private static CanLinkAccountsResult canLinkAccountsHelper(TransactionConnection

if (recipeUserIdLM.email != null) {
AuthRecipeUserInfo[] usersWithSameEmail = storage
.listPrimaryUsersByEmail_Transaction(tenantIdentifier, con,
.listPrimaryUsersByEmail_Transaction(appIdentifierWithStorage, con,
recipeUserIdLM.email);
for (AuthRecipeUserInfo user : usersWithSameEmail) {
if (!user.tenantIds.contains(tenantId)) {
continue;
}
if (user.isPrimaryUser && !user.getSupertokensUserId().equals(primaryUser.getSupertokensUserId())) {
throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(user.getSupertokensUserId(),
"This user's email is already associated with another user ID");
Expand All @@ -279,9 +283,12 @@ private static CanLinkAccountsResult canLinkAccountsHelper(TransactionConnection

if (recipeUserIdLM.phoneNumber != null) {
AuthRecipeUserInfo[] usersWithSamePhoneNumber = storage
.listPrimaryUsersByPhoneNumber_Transaction(tenantIdentifier, con,
.listPrimaryUsersByPhoneNumber_Transaction(appIdentifierWithStorage, con,
recipeUserIdLM.phoneNumber);
for (AuthRecipeUserInfo user : usersWithSamePhoneNumber) {
if (!user.tenantIds.contains(tenantId)) {
continue;
}
if (user.isPrimaryUser && !user.getSupertokensUserId().equals(primaryUser.getSupertokensUserId())) {
throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(user.getSupertokensUserId(),
"This user's phone number is already associated with another user" +
Expand All @@ -291,16 +298,22 @@ private static CanLinkAccountsResult canLinkAccountsHelper(TransactionConnection
}

if (recipeUserIdLM.thirdParty != null) {
AuthRecipeUserInfo userWithSameThirdParty = storage
.getPrimaryUsersByThirdPartyInfo_Transaction(tenantIdentifier, con,
AuthRecipeUserInfo[] usersWithSameThirdParty = storage
.listPrimaryUsersByThirdPartyInfo_Transaction(appIdentifierWithStorage, con,
recipeUserIdLM.thirdParty.id, recipeUserIdLM.thirdParty.userId);
if (userWithSameThirdParty != null && userWithSameThirdParty.isPrimaryUser &&
!userWithSameThirdParty.getSupertokensUserId().equals(primaryUser.getSupertokensUserId())) {
throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(
userWithSameThirdParty.getSupertokensUserId(),
"This user's third party login is already associated with another" +
" user ID");
for (AuthRecipeUserInfo userWithSameThirdParty : usersWithSameThirdParty) {
if (!userWithSameThirdParty.tenantIds.contains(tenantId)) {
continue;
}
if (userWithSameThirdParty.isPrimaryUser &&
!userWithSameThirdParty.getSupertokensUserId().equals(primaryUser.getSupertokensUserId())) {
throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(
userWithSameThirdParty.getSupertokensUserId(),
"This user's third party login is already associated with another" +
" user ID");
}
}

}
}

Expand Down Expand Up @@ -470,9 +483,12 @@ private static CreatePrimaryUserResult canCreatePrimaryUserHelper(TransactionCon

if (loginMethod.email != null) {
AuthRecipeUserInfo[] usersWithSameEmail = storage
.listPrimaryUsersByEmail_Transaction(tenantIdentifier, con,
.listPrimaryUsersByEmail_Transaction(appIdentifierWithStorage, 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");
Expand All @@ -482,7 +498,7 @@ private static CreatePrimaryUserResult canCreatePrimaryUserHelper(TransactionCon

if (loginMethod.phoneNumber != null) {
AuthRecipeUserInfo[] usersWithSamePhoneNumber = storage
.listPrimaryUsersByPhoneNumber_Transaction(tenantIdentifier, con,
.listPrimaryUsersByPhoneNumber_Transaction(appIdentifierWithStorage, con,
loginMethod.phoneNumber);
for (AuthRecipeUserInfo user : usersWithSamePhoneNumber) {
if (user.isPrimaryUser) {
Expand All @@ -494,14 +510,19 @@ private static CreatePrimaryUserResult canCreatePrimaryUserHelper(TransactionCon
}

if (loginMethod.thirdParty != null) {
AuthRecipeUserInfo userWithSameThirdParty = storage
.getPrimaryUsersByThirdPartyInfo_Transaction(tenantIdentifier, con,
AuthRecipeUserInfo[] usersWithSameThirdParty = storage
.listPrimaryUsersByThirdPartyInfo_Transaction(appIdentifierWithStorage, con,
loginMethod.thirdParty.id, loginMethod.thirdParty.userId);
if (userWithSameThirdParty != null && userWithSameThirdParty.isPrimaryUser) {
throw new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException(
userWithSameThirdParty.getSupertokensUserId(),
"This user's third party login is already associated with another" +
" user ID");
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");
}
}
}
}
Expand Down
13 changes: 4 additions & 9 deletions src/main/java/io/supertokens/emailpassword/EmailPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -603,20 +603,15 @@ public static void updateUsersEmailOrPassword(AppIdentifierWithStorage appIdenti
if (email != null) {
if (user.isPrimaryUser) {
for (String tenantId : user.tenantIds) {
// we do not bother with getting the tenantIdentifierWithStorage here because
// we get the tenants from the user itself, and the user can only be shared across
// tenants of the same storage - therefore, the storage will be the same.
TenantIdentifier tenantIdentifier = new TenantIdentifier(
appIdentifierWithStorage.getConnectionUriDomain(),
appIdentifierWithStorage.getAppId(),
tenantId);

AuthRecipeUserInfo[] existingUsersWithNewEmail =
authRecipeStorage.listPrimaryUsersByEmail_Transaction(
tenantIdentifier, transaction,
appIdentifierWithStorage, transaction,
email);

for (AuthRecipeUserInfo userWithSameEmail : existingUsersWithNewEmail) {
if (!userWithSameEmail.tenantIds.contains(tenantId)) {
continue;
}
if (userWithSameEmail.isPrimaryUser && !userWithSameEmail.getSupertokensUserId().equals(user.getSupertokensUserId())) {
throw new StorageTransactionLogicException(
new EmailChangeNotAllowedException());
Expand Down
63 changes: 33 additions & 30 deletions src/main/java/io/supertokens/inmemorydb/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -2758,44 +2758,47 @@ public AuthRecipeUserInfo getPrimaryUserById_Transaction(AppIdentifier appIdenti
}

@Override
public AuthRecipeUserInfo[] listPrimaryUsersByEmail_Transaction(TenantIdentifier tenantIdentifier,
public AuthRecipeUserInfo[] listPrimaryUsersByEmail_Transaction(AppIdentifier appIdentifier,
TransactionConnection con, String email)
throws StorageQueryException {
try {
Connection sqlCon = (Connection) con.getConnection();
return GeneralQueries.listPrimaryUsersByEmail_Transaction(this, sqlCon, tenantIdentifier, email);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
return null; // TODO
// try {
// Connection sqlCon = (Connection) con.getConnection();
// return GeneralQueries.listPrimaryUsersByEmail_Transaction(this, sqlCon, appIdentifier, email);
// } catch (SQLException e) {
// throw new StorageQueryException(e);
// }
}

@Override
public AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber_Transaction(TenantIdentifier tenantIdentifier,
public AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber_Transaction(AppIdentifier appIdentifier,
TransactionConnection con,
String phoneNumber)
throws StorageQueryException {
try {
Connection sqlCon = (Connection) con.getConnection();
return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, tenantIdentifier,
phoneNumber);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
public AuthRecipeUserInfo getPrimaryUsersByThirdPartyInfo_Transaction(TenantIdentifier tenantIdentifier,
TransactionConnection con,
String thirdPartyId,
String thirdPartyUserId)
throws StorageQueryException {
try {
Connection sqlCon = (Connection) con.getConnection();
return GeneralQueries.getPrimaryUsersByThirdPartyInfo_Transaction(this, sqlCon, tenantIdentifier,
thirdPartyId, thirdPartyUserId);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
return null; // TODO
// try {
// Connection sqlCon = (Connection) con.getConnection();
// return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, tenantIdentifier,
// phoneNumber);
// } catch (SQLException e) {
// throw new StorageQueryException(e);
// }
}

@Override
public AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo_Transaction(AppIdentifier appIdentifier,
TransactionConnection con,
String thirdPartyId,
String thirdPartyUserId)
throws StorageQueryException {
return null; // TODO
// try {
// Connection sqlCon = (Connection) con.getConnection();
// return GeneralQueries.getPrimaryUsersByThirdPartyInfo_Transaction(this, sqlCon, tenantIdentifier,
// thirdPartyId, thirdPartyUserId);
// } catch (SQLException e) {
// throw new StorageQueryException(e);
// }
}

@Override
Expand Down
13 changes: 4 additions & 9 deletions src/main/java/io/supertokens/passwordless/Passwordless.java
Original file line number Diff line number Diff line change
Expand Up @@ -710,20 +710,15 @@ public static void updateUser(AppIdentifierWithStorage appIdentifierWithStorage,
if (emailUpdate != null && !Objects.equals(emailUpdate.newValue, lM.email)) {
if (user.isPrimaryUser) {
for (String tenantId : user.tenantIds) {
// we do not bother with getting the tenantIdentifierWithStorage here because
// we get the tenants from the user itself, and the user can only be shared across
// tenants of the same storage - therefore, the storage will be the same.
TenantIdentifier tenantIdentifier = new TenantIdentifier(
appIdentifierWithStorage.getConnectionUriDomain(),
appIdentifierWithStorage.getAppId(),
tenantId);

AuthRecipeUserInfo[] existingUsersWithNewEmail =
authRecipeSQLStorage.listPrimaryUsersByEmail_Transaction(
tenantIdentifier, con,
appIdentifierWithStorage, con,
emailUpdate.newValue);

for (AuthRecipeUserInfo userWithSameEmail : existingUsersWithNewEmail) {
if (!userWithSameEmail.tenantIds.contains(tenantId)) {
continue;
}
if (userWithSameEmail.isPrimaryUser && !userWithSameEmail.getSupertokensUserId().equals(user.getSupertokensUserId())) {
throw new StorageTransactionLogicException(
new EmailChangeNotAllowedException());
Expand Down
25 changes: 14 additions & 11 deletions src/main/java/io/supertokens/thirdparty/ThirdParty.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,18 @@ private static SignInUpResponse signInUpHelper(TenantIdentifierWithStorage tenan
(AuthRecipeSQLStorage) tenantIdentifierWithStorage.getAuthRecipeStorage();

storage.startTransaction(con -> {
AuthRecipeUserInfo userFromDb = authRecipeStorage.getPrimaryUsersByThirdPartyInfo_Transaction(
tenantIdentifierWithStorage,
AuthRecipeUserInfo userFromDb = null;

AuthRecipeUserInfo[] usersFromDb = authRecipeStorage.listPrimaryUsersByThirdPartyInfo_Transaction(
appIdentifier,
con,
thirdPartyId, thirdPartyUserId);
for (AuthRecipeUserInfo user : usersFromDb) {
if (user.tenantIds.contains(tenantIdentifierWithStorage.getTenantId())) {
userFromDb = user;
break;
}
}

if (userFromDb == null) {
storage.commitTransaction(con);
Expand All @@ -246,19 +254,14 @@ private static SignInUpResponse signInUpHelper(TenantIdentifierWithStorage tenan
// email, and if they do, then we do not allow the update.
if (userFromDb.isPrimaryUser) {
for (String tenantId : userFromDb.tenantIds) {
// we do not bother with getting the tenantIdentifierWithStorage here because
// we get the tenants from the user itself, and the user can only be shared across
// tenants of the same storage - therefore, the storage will be the same.
TenantIdentifier tenantIdentifier = new TenantIdentifier(
tenantIdentifierWithStorage.getConnectionUriDomain(),
tenantIdentifierWithStorage.getAppId(),
tenantId);

AuthRecipeUserInfo[] userBasedOnEmail =
authRecipeStorage.listPrimaryUsersByEmail_Transaction(
tenantIdentifier, con, email
appIdentifier, con, email
);
for (AuthRecipeUserInfo userWithSameEmail : userBasedOnEmail) {
if (!userWithSameEmail.tenantIds.contains(tenantId)) {
continue;
}
if (userWithSameEmail.isPrimaryUser &&
!userWithSameEmail.getSupertokensUserId().equals(userFromDb.getSupertokensUserId())) {
throw new StorageTransactionLogicException(
Expand Down
Loading

0 comments on commit e5ad501

Please sign in to comment.