Skip to content

Commit

Permalink
fix: update custom liquibase script to manage duplicates on organizat…
Browse files Browse the repository at this point in the history
…ion users

fixes AM-942
  • Loading branch information
leleueri committed Oct 12, 2023
1 parent 8288a14 commit b3fe97e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@
*/
public class UsernameUniquenessMigration implements CustomSqlChange {
public static final String TABLE_USERS = "users";
public static final String TABLE_ORGANIZATION_USERS = "organization_users";
private final Logger logger = LoggerFactory.getLogger(UsernameUniquenessMigration.class);

private int counter = 0;

private ObjectMapper mapper = new ObjectMapper();

@Override
Expand All @@ -57,9 +55,7 @@ public SqlStatement[] generateStatements(Database database) throws CustomChangeE
try {
JdbcConnection connection = (JdbcConnection) database.getConnection();

Map<String, List<User>> duplicatesUsersGroupByUsernameAndSource = searchDuplicatesGroupedByUsernameAndSource(connection);

logger.info("{} duplicate usernames found", counter);
Map<String, List<User>> duplicatesUsersGroupByUsernameAndSource = searchDuplicatesGroupedByUsernameAndSource(connection, TABLE_USERS);

// boolean to keep in memory if the process must fail
// in order to go through all the duplicates to see all potential errors.
Expand Down Expand Up @@ -100,6 +96,21 @@ public SqlStatement[] generateStatements(Database database) throws CustomChangeE
}
}

Map<String, List<User>> duplicatesOrgUsersGroupByUsernameAndSource = searchDuplicatesGroupedByUsernameAndSource(connection, TABLE_ORGANIZATION_USERS);
for (Map.Entry<String, List<User>> entries : duplicatesOrgUsersGroupByUsernameAndSource.entrySet()) {
List<User> duplicates = entries.getValue();
User referenceUser = duplicates.get(0);

if (!referenceUser.getSource().equalsIgnoreCase("gravitee") && !referenceUser.getSource().equalsIgnoreCase("cockpit")) {
logger.error("Organization Username '{}' migration only manages gravitee & cockpit identity providers",
referenceUser.getUsername(),
referenceUser.getSource());
needToFail = true;
} else {
statements.addAll(generateStatementToRenameDuplicatedOrgUsers(database, duplicates));
}
}

if (needToFail) {
throw new CustomChangeException("Some duplicates can't be processed automatically, liquibase will fail");
}
Expand All @@ -111,8 +122,27 @@ public SqlStatement[] generateStatements(Database database) throws CustomChangeE
}
}

private List<SqlStatement> generateStatementToRenameDuplicatedOrgUsers(Database database, List<User> duplicates) {
List<SqlStatement> statementsToApply = new ArrayList<>();
for (int i = 1; i < duplicates.size(); ++i) {
final User duplicateToUpdate = duplicates.get(i);
final String updatedUsername = duplicateToUpdate.getUsername()+"_"+i+"_TO_RENAME_OR_DELETE";
logger.info("Renaming organization username '{}' to '{}' into tables '" + TABLE_ORGANIZATION_USERS + "' (user_id: {})",
duplicateToUpdate.getUsername(),
updatedUsername,
duplicateToUpdate.getId());

SqlStatement updateUsersTable = new UpdateStatement(database.getDefaultCatalogName(), database.getDefaultSchemaName(), TABLE_ORGANIZATION_USERS)
.addNewColumnValue("username", updatedUsername)
.setWhereClause(String.format("id='%s'", duplicateToUpdate.getId()));
statementsToApply.add(updateUsersTable);
}
return statementsToApply;
}

private List<SqlStatement> generateStatementToRenameDuplicatedUsers(Database database, List<User> duplicates, String idpTable, String usernameColumn, String idColumn) {
List<SqlStatement> statementsToApply = new ArrayList<>();

for (int i = 1; i < duplicates.size(); ++i) {
final User duplicateToUpdate = duplicates.get(i);
final String updatedUsername = duplicateToUpdate.getUsername()+"_"+i+"_TO_RENAME_OR_DELETE";
Expand All @@ -136,12 +166,13 @@ private List<SqlStatement> generateStatementToRenameDuplicatedUsers(Database dat
return statementsToApply;
}

private Map<String, List<User>> searchDuplicatesGroupedByUsernameAndSource(JdbcConnection connection) throws SQLException, DatabaseException {
private Map<String, List<User>> searchDuplicatesGroupedByUsernameAndSource(JdbcConnection connection, String table) throws SQLException, DatabaseException {
int userCounter = 0;
PreparedStatement searchDuplicates = connection.prepareStatement("select u.*\n" +
"from users u,\n" +
"from "+table+" u,\n" +
"(select username, source\n" +
"from (select username, source, count(username) as count\n" +
"from users\n" +
"from "+table + "\n" +
"group by source, username) as multiEntries\n" +
"where multiEntries.count > 1) duplicateUser\n" +
"where u.username = duplicateUser.username\n" +
Expand All @@ -167,17 +198,20 @@ private Map<String, List<User>> searchDuplicatesGroupedByUsernameAndSource(JdbcC
}
duplicatesUsersGroupByUsernameAndSource.get(groupKey).add(currentUser);

counter++;
userCounter++;
}

duplicateUsers.close();
searchDuplicates.close();

logger.info("{} duplicate usernames found into {} table", userCounter, table);

return duplicatesUsersGroupByUsernameAndSource;
}

@Override
public String getConfirmationMessage() {
return this.counter + " usernames processed successfully to avoid duplicates";
return "Usernames processed successfully to avoid duplicates";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
databaseChangeLog:
- changeSet:
id: 3.19.21-org-users-add-username-unique-constraints
author: GraviteeSource Team
changes:
#############################
# users Table, add unique constraints to the username field
############################
- addUniqueConstraint:
tableName: organization_users
columnNames: username, source
constraintName: org_users_username_source_unique
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ databaseChangeLog:
- file: liquibase/changelogs/v3_19_13/3.19.13-alter-i18n_dictionary_entries-column-length.yml
- include:
- file: liquibase/changelogs/v3_19_21/3.19.21-migrate-users_username_unique.yml
- include:
- file: liquibase/changelogs/v3_19_21/3.19.21-alter-org_users_username_unique.yml
- include:
- file: liquibase/changelogs/v3_19_21/3.19.21-alter-users_username_unique.yml
- include:
Expand Down

0 comments on commit b3fe97e

Please sign in to comment.