Skip to content

Commit

Permalink
fix: multitenant user association (#808)
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc authored Sep 13, 2023
1 parent 825c13f commit f721e15
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 156 deletions.
158 changes: 71 additions & 87 deletions src/main/java/io/supertokens/inmemorydb/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -2288,77 +2288,64 @@ public TenantConfig[] getAllTenants() throws StorageQueryException {
}

@Override
public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection conn, String userId)
public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, String userId)
throws StorageQueryException, TenantOrAppNotFoundException, DuplicateEmailException,
DuplicateThirdPartyUserException, DuplicatePhoneNumberException, UnknownUserIdException {
Connection sqlCon = (Connection) con.getConnection();
try {
return this.startTransaction(con -> {
Connection sqlCon = (Connection) con.getConnection();
try {
String recipeId = GeneralQueries.getRecipeIdForUser_Transaction(this, sqlCon, tenantIdentifier,
userId);

if (recipeId == null) {
throw new StorageTransactionLogicException(new UnknownUserIdException());
}

boolean added;
if (recipeId.equals("emailpassword")) {
added = EmailPasswordQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier,
userId);
} else if (recipeId.equals("thirdparty")) {
added = ThirdPartyQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, userId);
} else if (recipeId.equals("passwordless")) {
added = PasswordlessQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier,
userId);
} else {
throw new IllegalStateException("Should never come here!");
}
String recipeId = GeneralQueries.getRecipeIdForUser_Transaction(this, sqlCon, tenantIdentifier,
userId);

sqlCon.commit();
return added;
} catch (SQLException throwables) {
throw new StorageTransactionLogicException(throwables);
}
});
} catch (StorageTransactionLogicException e) {
if (e.actualException instanceof SQLException) {
SQLiteConfig config = Config.getConfig(this);
String serverErrorMessage = e.actualException.getMessage();
if (recipeId == null) {
throw new UnknownUserIdException();
}

if (isForeignKeyConstraintError(
serverErrorMessage,
config.getTenantsTable(),
new String[]{"app_id", "tenant_id"},
new Object[]{tenantIdentifier.getAppId(), tenantIdentifier.getTenantId()})) {
throw new TenantOrAppNotFoundException(tenantIdentifier);
}
if (isUniqueConstraintError(serverErrorMessage, config.getEmailPasswordUserToTenantTable(),
new String[]{"app_id", "tenant_id", "email"})) {
throw new DuplicateEmailException();
}
if (isUniqueConstraintError(serverErrorMessage, config.getThirdPartyUserToTenantTable(),
new String[]{"app_id", "tenant_id", "third_party_id", "third_party_user_id"})) {
throw new DuplicateThirdPartyUserException();
}
if (isUniqueConstraintError(serverErrorMessage,
Config.getConfig(this).getPasswordlessUserToTenantTable(),
new String[]{"app_id", "tenant_id", "phone_number"})) {
throw new DuplicatePhoneNumberException();
}
if (isUniqueConstraintError(serverErrorMessage,
Config.getConfig(this).getPasswordlessUserToTenantTable(),
new String[]{"app_id", "tenant_id", "email"})) {
throw new DuplicateEmailException();
}
boolean added;
if (recipeId.equals("emailpassword")) {
added = EmailPasswordQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier,
userId);
} else if (recipeId.equals("thirdparty")) {
added = ThirdPartyQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, userId);
} else if (recipeId.equals("passwordless")) {
added = PasswordlessQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier,
userId);
} else {
throw new IllegalStateException("Should never come here!");
}

throw new StorageQueryException(e.actualException);
} else if (e.actualException instanceof UnknownUserIdException) {
throw (UnknownUserIdException) e.actualException;
} else if (e.actualException instanceof StorageQueryException) {
throw (StorageQueryException) e.actualException;
sqlCon.commit();
return added;
} catch (SQLException throwables) {
SQLiteConfig config = Config.getConfig(this);
String serverErrorMessage = throwables.getMessage();

if (isForeignKeyConstraintError(
serverErrorMessage,
config.getTenantsTable(),
new String[]{"app_id", "tenant_id"},
new Object[]{tenantIdentifier.getAppId(), tenantIdentifier.getTenantId()})) {
throw new TenantOrAppNotFoundException(tenantIdentifier);
}
throw new StorageQueryException(e.actualException);
if (isUniqueConstraintError(serverErrorMessage, config.getEmailPasswordUserToTenantTable(),
new String[]{"app_id", "tenant_id", "email"})) {
throw new DuplicateEmailException();
}
if (isUniqueConstraintError(serverErrorMessage, config.getThirdPartyUserToTenantTable(),
new String[]{"app_id", "tenant_id", "third_party_id", "third_party_user_id"})) {
throw new DuplicateThirdPartyUserException();
}
if (isUniqueConstraintError(serverErrorMessage,
Config.getConfig(this).getPasswordlessUserToTenantTable(),
new String[]{"app_id", "tenant_id", "phone_number"})) {
throw new DuplicatePhoneNumberException();
}
if (isUniqueConstraintError(serverErrorMessage,
Config.getConfig(this).getPasswordlessUserToTenantTable(),
new String[]{"app_id", "tenant_id", "email"})) {
throw new DuplicateEmailException();
}

throw new StorageQueryException(throwables);
}
}

Expand Down Expand Up @@ -2804,28 +2791,26 @@ public AuthRecipeUserInfo getPrimaryUserById_Transaction(AppIdentifier appIdenti
public AuthRecipeUserInfo[] listPrimaryUsersByEmail_Transaction(AppIdentifier appIdentifier,
TransactionConnection con, String email)
throws StorageQueryException {
return null; // TODO
// try {
// Connection sqlCon = (Connection) con.getConnection();
// return GeneralQueries.listPrimaryUsersByEmail_Transaction(this, sqlCon, appIdentifier, email);
// } catch (SQLException e) {
// throw new StorageQueryException(e);
// }
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(AppIdentifier appIdentifier,
TransactionConnection con,
String phoneNumber)
throws StorageQueryException {
return null; // TODO
// try {
// Connection sqlCon = (Connection) con.getConnection();
// return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, tenantIdentifier,
// phoneNumber);
// } catch (SQLException e) {
// throw new StorageQueryException(e);
// }
try {
Connection sqlCon = (Connection) con.getConnection();
return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, appIdentifier,
phoneNumber);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
Expand All @@ -2842,14 +2827,13 @@ public AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo_Transaction(AppIden
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);
// }
try {
Connection sqlCon = (Connection) con.getConnection();
return GeneralQueries.getPrimaryUsersByThirdPartyInfo_Transaction(this, sqlCon, appIdentifier,
thirdPartyId, thirdPartyUserId);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,19 +397,18 @@ public static List<LoginMethod> getUsersInfoUsingIdList(Start start, Connection
return Collections.emptyList();
}

public static String lockEmailAndTenant_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier,
String email) throws SQLException, StorageQueryException {
public static String lockEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier,
String email) throws SQLException, StorageQueryException {
// normally the query below will use a for update, but sqlite doesn't support it.
((ConnectionWithLocks) con).lock(
tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + email +
Config.getConfig(start).getEmailPasswordUserToTenantTable());
appIdentifier.getAppId() + "~" + email +
Config.getConfig(start).getEmailPasswordUsersTable());

String QUERY = "SELECT user_id FROM " + getConfig(start).getEmailPasswordUserToTenantTable() +
" WHERE app_id = ? AND tenant_id = ? AND email = ?";
String QUERY = "SELECT user_id FROM " + getConfig(start).getEmailPasswordUsersTable() +
" WHERE app_id = ? AND email = ?";
return execute(con, QUERY, pst -> {
pst.setString(1, tenantIdentifier.getAppId());
pst.setString(2, tenantIdentifier.getTenantId());
pst.setString(3, email);
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, email);
}, result -> {
if (result.next()) {
return result.getString("user_id");
Expand Down Expand Up @@ -439,6 +438,27 @@ public static String getPrimaryUserIdUsingEmail(Start start, Connection con, Ten
});
}

public static List<String> getPrimaryUserIdsUsingEmail(Start start, Connection con, AppIdentifier appIdentifier,
String email)
throws StorageQueryException, SQLException {
String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id "
+ "FROM " + getConfig(start).getEmailPasswordUsersTable() + " AS ep" +
" JOIN " + getConfig(start).getUsersTable() + " AS all_users" +
" ON ep.app_id = all_users.app_id AND ep.user_id = all_users.user_id" +
" WHERE ep.app_id = ? AND ep.email = ?";

return execute(con, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, email);
}, result -> {
List<String> userIds = new ArrayList<>();
while (result.next()) {
userIds.add(result.getString("user_id"));
}
return userIds;
});
}

public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlCon,
TenantIdentifier tenantIdentifier, String userId)
throws SQLException, StorageQueryException {
Expand Down
Loading

0 comments on commit f721e15

Please sign in to comment.