diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/util/OpenMetadataOperations.java b/openmetadata-service/src/main/java/org/openmetadata/service/util/OpenMetadataOperations.java index 02be91fc84e..3e55072b5b7 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/util/OpenMetadataOperations.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/util/OpenMetadataOperations.java @@ -4,7 +4,9 @@ import static org.flywaydb.core.internal.info.MigrationInfoDumper.dumpToAsciiTab import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; import static org.openmetadata.service.Entity.FIELD_OWNERS; import static org.openmetadata.service.formatter.decorators.MessageDecorator.getDateStringEpochMilli; +import static org.openmetadata.service.jdbi3.UserRepository.AUTH_MECHANISM_FIELD; import static org.openmetadata.service.util.AsciiTable.printOpenMetadataText; +import static org.openmetadata.service.util.UserUtil.updateUserWithHashedPwd; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; @@ -23,6 +25,7 @@ import java.io.File; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -41,6 +44,8 @@ import org.openmetadata.schema.ServiceEntityInterface; import org.openmetadata.schema.entity.app.App; import org.openmetadata.schema.entity.app.AppRunRecord; import org.openmetadata.schema.entity.services.ingestionPipelines.IngestionPipeline; +import org.openmetadata.schema.entity.teams.User; +import org.openmetadata.schema.services.connections.metadata.AuthProvider; import org.openmetadata.schema.settings.Settings; import org.openmetadata.schema.settings.SettingsType; import org.openmetadata.schema.system.EventPublisherJob; @@ -60,6 +65,7 @@ import org.openmetadata.service.jdbi3.IngestionPipelineRepository; import org.openmetadata.service.jdbi3.ListFilter; import org.openmetadata.service.jdbi3.MigrationDAO; import org.openmetadata.service.jdbi3.SystemRepository; +import org.openmetadata.service.jdbi3.UserRepository; import org.openmetadata.service.jdbi3.locator.ConnectionType; import org.openmetadata.service.migration.api.MigrationWorkflow; import org.openmetadata.service.resources.CollectionRegistry; @@ -166,13 +172,12 @@ public class OpenMetadataOperations implements Callable { public Integer syncEmailFromEnv() { try { parseConfig(); - Entity.setCollectionDAO(jdbi.onDemand(CollectionDAO.class)); - SystemRepository systemRepository = new SystemRepository(); Settings updatedSettings = new Settings() .withConfigType(SettingsType.EMAIL_CONFIGURATION) .withConfigValue(config.getSmtpSettings()); - systemRepository.createOrUpdate(updatedSettings); + Entity.getSystemRepository().createOrUpdate(updatedSettings); + LOG.info("Synced Email Configuration from Environment."); return 0; } catch (Exception e) { LOG.error("Email Sync failed due to ", e); @@ -221,6 +226,58 @@ public class OpenMetadataOperations implements Callable { } } + @Command(name = "reset-password", description = "Reset the password for a user.") + public Integer resetUserPassword( + @Option( + names = {"-e", "--email"}, + description = "Email for which to reset the password.", + required = true) + String email, + @Option( + names = {"-p", "--password"}, + description = "Enter user password", + arity = "0..1", + interactive = true, + required = true) + char[] password) { + try { + LOG.info("Resetting password for user : {}", email); + if (nullOrEmpty(password)) { + throw new IllegalArgumentException("Password cannot be empty."); + } + parseConfig(); + CollectionRegistry.initialize(); + AuthProvider authProvider = config.getAuthenticationConfiguration().getProvider(); + + // Only Basic Auth provider is supported for password reset + if (!authProvider.equals(AuthProvider.BASIC)) { + LOG.error("Auth Provider is Not Basic. Cannot apply Password"); + return 1; + } + + UserRepository userRepository = (UserRepository) Entity.getEntityRepository(Entity.USER); + Set fieldList = new HashSet<>(userRepository.getPatchFields().getFieldList()); + fieldList.add(AUTH_MECHANISM_FIELD); + User originalUser = userRepository.getByEmail(null, email, new EntityUtil.Fields(fieldList)); + + // Check if the user is a bot user + if (Boolean.TRUE.equals(originalUser.getIsBot())) { + LOG.error("Bot user : {} cannot have password.", originalUser.getName()); + return 1; + } + + User updatedUser = JsonUtils.deepCopy(originalUser, User.class); + String inputPwd = new String(password); + updateUserWithHashedPwd(updatedUser, inputPwd); + UserUtil.addOrUpdateUser(updatedUser); + LOG.info("Password updated successfully."); + return 0; + } catch (Exception e) { + LOG.error("Failed to reset user password.", e); + return 1; + } + } + @Command( name = "migrate", description = "Migrates the OpenMetadata database schema and search index mappings.") @@ -652,6 +709,7 @@ public class OpenMetadataOperations implements Callable { collectionDAO = jdbi.onDemand(CollectionDAO.class); Entity.setSearchRepository(searchRepository); Entity.setCollectionDAO(collectionDAO); + Entity.setSystemRepository(new SystemRepository()); Entity.initializeRepositories(config, jdbi); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/util/UserUtil.java b/openmetadata-service/src/main/java/org/openmetadata/service/util/UserUtil.java index 01fe23b3a6c..6e27e01efdd 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/util/UserUtil.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/util/UserUtil.java @@ -19,6 +19,7 @@ import static org.openmetadata.schema.entity.teams.AuthenticationMechanism.AuthT import static org.openmetadata.schema.type.Include.NON_DELETED; import static org.openmetadata.service.Entity.ADMIN_ROLE; import static org.openmetadata.service.Entity.ADMIN_USER_NAME; +import static org.openmetadata.service.jdbi3.UserRepository.AUTH_MECHANISM_FIELD; import at.favre.lib.crypto.bcrypt.BCrypt; import java.util.ArrayList; @@ -62,8 +63,18 @@ public final class UserUtil { public static void addUsers( AuthProvider authProvider, Set adminUsers, String domain, Boolean isAdmin) { try { - for (String username : adminUsers) { - createOrUpdateUser(authProvider, username, domain, isAdmin); + for (String keyValue : adminUsers) { + String userName = ""; + String password = ""; + if (keyValue.contains(":")) { + String[] keyValueArray = keyValue.split(":"); + userName = keyValueArray[0]; + password = keyValueArray[1]; + } else { + userName = keyValue; + password = getPassword(userName); + } + createOrUpdateUser(authProvider, userName, password, domain, isAdmin); } } catch (Exception ex) { LOG.error("[BootstrapUser] Encountered Exception while bootstrapping admin user", ex); @@ -71,27 +82,26 @@ public final class UserUtil { } private static void createOrUpdateUser( - AuthProvider authProvider, String username, String domain, Boolean isAdmin) { + AuthProvider authProvider, String username, String password, String domain, Boolean isAdmin) { UserRepository userRepository = (UserRepository) Entity.getEntityRepository(Entity.USER); User updatedUser = null; try { // Create Required Fields List Set fieldList = new HashSet<>(userRepository.getPatchFields().getFieldList()); - fieldList.add("authenticationMechanism"); + fieldList.add(AUTH_MECHANISM_FIELD); // Fetch Original User, is available User originalUser = userRepository.getByName(null, username, new Fields(fieldList)); if (Boolean.FALSE.equals(originalUser.getIsBot()) - && Boolean.FALSE.equals(originalUser.getIsAdmin())) { + && Boolean.TRUE.equals(originalUser.getIsAdmin())) { updatedUser = originalUser; // Update Auth Mechanism if not present, and send mail to the user if (authProvider.equals(AuthProvider.BASIC)) { if (originalUser.getAuthenticationMechanism() == null || originalUser.getAuthenticationMechanism().equals(new AuthenticationMechanism())) { - String randomPwd = getPassword(username); - updateUserWithHashedPwd(updatedUser, randomPwd); - EmailUtil.sendInviteMailToAdmin(updatedUser, randomPwd); + updateUserWithHashedPwd(updatedUser, password); + EmailUtil.sendInviteMailToAdmin(updatedUser, password); } } else { updatedUser.setAuthenticationMechanism(new AuthenticationMechanism()); @@ -114,9 +124,8 @@ public final class UserUtil { updatedUser = user(username, domain, username).withIsAdmin(isAdmin).withIsEmailVerified(true); // Update Auth Mechanism if not present, and send mail to the user if (authProvider.equals(AuthProvider.BASIC)) { - String randomPwd = getPassword(username); - updateUserWithHashedPwd(updatedUser, randomPwd); - EmailUtil.sendInviteMailToAdmin(updatedUser, randomPwd); + updateUserWithHashedPwd(updatedUser, password); + EmailUtil.sendInviteMailToAdmin(updatedUser, password); } }