mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-03 06:03:12 +00:00
[FIX] ldap User Name (#17764)
* migrate userName to emailPrefix for ldap auth provider. * migrate userName to emailPrefix for ldap auth provider. * fix migration. * move migration to v155 * Update Ldap Authenticator * Fix Ldap Issue on Login --------- Co-authored-by: Mohit Yadav <105265192+mohityadav766@users.noreply.github.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com>
This commit is contained in:
parent
c1e20873b1
commit
bc3d4c778e
@ -454,6 +454,7 @@ public class OpenMetadataApplication extends Application<OpenMetadataApplication
|
|||||||
connectionType,
|
connectionType,
|
||||||
conf.getMigrationConfiguration().getExtensionPath(),
|
conf.getMigrationConfiguration().getExtensionPath(),
|
||||||
conf.getPipelineServiceClientConfiguration(),
|
conf.getPipelineServiceClientConfiguration(),
|
||||||
|
conf.getAuthenticationConfiguration(),
|
||||||
false);
|
false);
|
||||||
migrationWorkflow.loadMigrations();
|
migrationWorkflow.loadMigrations();
|
||||||
migrationWorkflow.validateMigrationsForServer();
|
migrationWorkflow.validateMigrationsForServer();
|
||||||
|
@ -9,6 +9,7 @@ import java.util.Map;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jdbi.v3.core.Handle;
|
import org.jdbi.v3.core.Handle;
|
||||||
|
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
|
||||||
import org.openmetadata.sdk.PipelineServiceClientInterface;
|
import org.openmetadata.sdk.PipelineServiceClientInterface;
|
||||||
import org.openmetadata.service.clients.pipeline.PipelineServiceClientFactory;
|
import org.openmetadata.service.clients.pipeline.PipelineServiceClientFactory;
|
||||||
import org.openmetadata.service.jdbi3.CollectionDAO;
|
import org.openmetadata.service.jdbi3.CollectionDAO;
|
||||||
@ -24,6 +25,7 @@ public class MigrationProcessImpl implements MigrationProcess {
|
|||||||
protected CollectionDAO collectionDAO;
|
protected CollectionDAO collectionDAO;
|
||||||
protected Handle handle;
|
protected Handle handle;
|
||||||
protected PipelineServiceClientInterface pipelineServiceClient;
|
protected PipelineServiceClientInterface pipelineServiceClient;
|
||||||
|
protected AuthenticationConfiguration authenticationConfiguration;
|
||||||
private final MigrationFile migrationFile;
|
private final MigrationFile migrationFile;
|
||||||
|
|
||||||
public @Getter MigrationContext context;
|
public @Getter MigrationContext context;
|
||||||
@ -40,6 +42,7 @@ public class MigrationProcessImpl implements MigrationProcess {
|
|||||||
this.pipelineServiceClient =
|
this.pipelineServiceClient =
|
||||||
PipelineServiceClientFactory.createPipelineServiceClient(
|
PipelineServiceClientFactory.createPipelineServiceClient(
|
||||||
this.migrationFile.pipelineServiceClientConfiguration);
|
this.migrationFile.pipelineServiceClientConfiguration);
|
||||||
|
this.authenticationConfiguration = migrationFile.authenticationConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,6 +18,7 @@ import org.jdbi.v3.core.Handle;
|
|||||||
import org.jdbi.v3.core.Jdbi;
|
import org.jdbi.v3.core.Jdbi;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
||||||
|
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
|
||||||
import org.openmetadata.service.jdbi3.MigrationDAO;
|
import org.openmetadata.service.jdbi3.MigrationDAO;
|
||||||
import org.openmetadata.service.jdbi3.locator.ConnectionType;
|
import org.openmetadata.service.jdbi3.locator.ConnectionType;
|
||||||
import org.openmetadata.service.migration.QueryStatus;
|
import org.openmetadata.service.migration.QueryStatus;
|
||||||
@ -35,6 +36,7 @@ public class MigrationWorkflow {
|
|||||||
private final ConnectionType connectionType;
|
private final ConnectionType connectionType;
|
||||||
private final String extensionSQLScriptRootPath;
|
private final String extensionSQLScriptRootPath;
|
||||||
@Getter private final PipelineServiceClientConfiguration pipelineServiceClientConfiguration;
|
@Getter private final PipelineServiceClientConfiguration pipelineServiceClientConfiguration;
|
||||||
|
@Getter private final AuthenticationConfiguration authenticationConfiguration;
|
||||||
private final MigrationDAO migrationDAO;
|
private final MigrationDAO migrationDAO;
|
||||||
private final Jdbi jdbi;
|
private final Jdbi jdbi;
|
||||||
private final boolean forceMigrations;
|
private final boolean forceMigrations;
|
||||||
@ -47,6 +49,7 @@ public class MigrationWorkflow {
|
|||||||
ConnectionType connectionType,
|
ConnectionType connectionType,
|
||||||
String extensionSQLScriptRootPath,
|
String extensionSQLScriptRootPath,
|
||||||
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
||||||
|
AuthenticationConfiguration authenticationConfiguration,
|
||||||
boolean forceMigrations) {
|
boolean forceMigrations) {
|
||||||
this.jdbi = jdbi;
|
this.jdbi = jdbi;
|
||||||
this.migrationDAO = jdbi.onDemand(MigrationDAO.class);
|
this.migrationDAO = jdbi.onDemand(MigrationDAO.class);
|
||||||
@ -55,6 +58,7 @@ public class MigrationWorkflow {
|
|||||||
this.connectionType = connectionType;
|
this.connectionType = connectionType;
|
||||||
this.extensionSQLScriptRootPath = extensionSQLScriptRootPath;
|
this.extensionSQLScriptRootPath = extensionSQLScriptRootPath;
|
||||||
this.pipelineServiceClientConfiguration = pipelineServiceClientConfiguration;
|
this.pipelineServiceClientConfiguration = pipelineServiceClientConfiguration;
|
||||||
|
this.authenticationConfiguration = authenticationConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadMigrations() {
|
public void loadMigrations() {
|
||||||
@ -64,7 +68,8 @@ public class MigrationWorkflow {
|
|||||||
nativeSQLScriptRootPath,
|
nativeSQLScriptRootPath,
|
||||||
connectionType,
|
connectionType,
|
||||||
extensionSQLScriptRootPath,
|
extensionSQLScriptRootPath,
|
||||||
pipelineServiceClientConfiguration);
|
pipelineServiceClientConfiguration,
|
||||||
|
authenticationConfiguration);
|
||||||
// Filter Migrations to Be Run
|
// Filter Migrations to Be Run
|
||||||
this.migrations = filterAndGetMigrationsToRun(availableMigrations);
|
this.migrations = filterAndGetMigrationsToRun(availableMigrations);
|
||||||
}
|
}
|
||||||
@ -83,10 +88,15 @@ public class MigrationWorkflow {
|
|||||||
String nativeSQLScriptRootPath,
|
String nativeSQLScriptRootPath,
|
||||||
ConnectionType connectionType,
|
ConnectionType connectionType,
|
||||||
String extensionSQLScriptRootPath,
|
String extensionSQLScriptRootPath,
|
||||||
PipelineServiceClientConfiguration pipelineServiceClientConfiguration) {
|
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
||||||
|
AuthenticationConfiguration authenticationConfiguration) {
|
||||||
List<MigrationFile> availableOMNativeMigrations =
|
List<MigrationFile> availableOMNativeMigrations =
|
||||||
getMigrationFilesFromPath(
|
getMigrationFilesFromPath(
|
||||||
nativeSQLScriptRootPath, connectionType, pipelineServiceClientConfiguration, false);
|
nativeSQLScriptRootPath,
|
||||||
|
connectionType,
|
||||||
|
pipelineServiceClientConfiguration,
|
||||||
|
authenticationConfiguration,
|
||||||
|
false);
|
||||||
|
|
||||||
// If we only have OM migrations, return them
|
// If we only have OM migrations, return them
|
||||||
if (extensionSQLScriptRootPath == null || extensionSQLScriptRootPath.isEmpty()) {
|
if (extensionSQLScriptRootPath == null || extensionSQLScriptRootPath.isEmpty()) {
|
||||||
@ -96,7 +106,11 @@ public class MigrationWorkflow {
|
|||||||
// Otherwise, fetch the extension migrations and sort the executions
|
// Otherwise, fetch the extension migrations and sort the executions
|
||||||
List<MigrationFile> availableExtensionMigrations =
|
List<MigrationFile> availableExtensionMigrations =
|
||||||
getMigrationFilesFromPath(
|
getMigrationFilesFromPath(
|
||||||
extensionSQLScriptRootPath, connectionType, pipelineServiceClientConfiguration, true);
|
extensionSQLScriptRootPath,
|
||||||
|
connectionType,
|
||||||
|
pipelineServiceClientConfiguration,
|
||||||
|
authenticationConfiguration,
|
||||||
|
true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If we create migrations version as:
|
If we create migrations version as:
|
||||||
@ -114,6 +128,7 @@ public class MigrationWorkflow {
|
|||||||
String path,
|
String path,
|
||||||
ConnectionType connectionType,
|
ConnectionType connectionType,
|
||||||
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
||||||
|
AuthenticationConfiguration authenticationConfiguration,
|
||||||
Boolean isExtension) {
|
Boolean isExtension) {
|
||||||
return Arrays.stream(Objects.requireNonNull(new File(path).listFiles(File::isDirectory)))
|
return Arrays.stream(Objects.requireNonNull(new File(path).listFiles(File::isDirectory)))
|
||||||
.map(
|
.map(
|
||||||
@ -123,6 +138,7 @@ public class MigrationWorkflow {
|
|||||||
migrationDAO,
|
migrationDAO,
|
||||||
connectionType,
|
connectionType,
|
||||||
pipelineServiceClientConfiguration,
|
pipelineServiceClientConfiguration,
|
||||||
|
authenticationConfiguration,
|
||||||
isExtension))
|
isExtension))
|
||||||
.sorted()
|
.sorted()
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.openmetadata.service.migration.mysql.v155;
|
||||||
|
|
||||||
|
import static org.openmetadata.service.migration.utils.v155.MigrationUtil.updateUserNameToEmailPrefixForLdapAuthProvider;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.openmetadata.service.migration.api.MigrationProcessImpl;
|
||||||
|
import org.openmetadata.service.migration.utils.MigrationFile;
|
||||||
|
|
||||||
|
public class Migration extends MigrationProcessImpl {
|
||||||
|
|
||||||
|
public Migration(MigrationFile migrationFile) {
|
||||||
|
super(migrationFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public void runDataMigration() {
|
||||||
|
updateUserNameToEmailPrefixForLdapAuthProvider(
|
||||||
|
handle, collectionDAO, authenticationConfiguration, false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.openmetadata.service.migration.postgres.v155;
|
||||||
|
|
||||||
|
import static org.openmetadata.service.migration.utils.v155.MigrationUtil.updateUserNameToEmailPrefixForLdapAuthProvider;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.openmetadata.service.migration.api.MigrationProcessImpl;
|
||||||
|
import org.openmetadata.service.migration.utils.MigrationFile;
|
||||||
|
|
||||||
|
public class Migration extends MigrationProcessImpl {
|
||||||
|
|
||||||
|
public Migration(MigrationFile migrationFile) {
|
||||||
|
super(migrationFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public void runDataMigration() {
|
||||||
|
updateUserNameToEmailPrefixForLdapAuthProvider(
|
||||||
|
handle, collectionDAO, authenticationConfiguration, true);
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import org.flywaydb.core.internal.resource.filesystem.FileSystemResource;
|
|||||||
import org.flywaydb.core.internal.sqlscript.SqlStatementIterator;
|
import org.flywaydb.core.internal.sqlscript.SqlStatementIterator;
|
||||||
import org.flywaydb.database.mysql.MySQLParser;
|
import org.flywaydb.database.mysql.MySQLParser;
|
||||||
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
||||||
|
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
|
||||||
import org.openmetadata.service.jdbi3.MigrationDAO;
|
import org.openmetadata.service.jdbi3.MigrationDAO;
|
||||||
import org.openmetadata.service.jdbi3.locator.ConnectionType;
|
import org.openmetadata.service.jdbi3.locator.ConnectionType;
|
||||||
import org.openmetadata.service.util.EntityUtil;
|
import org.openmetadata.service.util.EntityUtil;
|
||||||
@ -23,6 +24,8 @@ public class MigrationFile implements Comparable<MigrationFile> {
|
|||||||
public final String version;
|
public final String version;
|
||||||
public final ConnectionType connectionType;
|
public final ConnectionType connectionType;
|
||||||
public final PipelineServiceClientConfiguration pipelineServiceClientConfiguration;
|
public final PipelineServiceClientConfiguration pipelineServiceClientConfiguration;
|
||||||
|
public final AuthenticationConfiguration authenticationConfiguration;
|
||||||
|
|
||||||
public final File dir;
|
public final File dir;
|
||||||
public final Boolean isExtension;
|
public final Boolean isExtension;
|
||||||
public final String dbPackageName;
|
public final String dbPackageName;
|
||||||
@ -38,6 +41,7 @@ public class MigrationFile implements Comparable<MigrationFile> {
|
|||||||
MigrationDAO migrationDAO,
|
MigrationDAO migrationDAO,
|
||||||
ConnectionType connectionType,
|
ConnectionType connectionType,
|
||||||
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
||||||
|
AuthenticationConfiguration authenticationConfiguration,
|
||||||
Boolean isExtension) {
|
Boolean isExtension) {
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
this.isExtension = isExtension;
|
this.isExtension = isExtension;
|
||||||
@ -45,6 +49,7 @@ public class MigrationFile implements Comparable<MigrationFile> {
|
|||||||
this.connectionType = connectionType;
|
this.connectionType = connectionType;
|
||||||
this.migrationDAO = migrationDAO;
|
this.migrationDAO = migrationDAO;
|
||||||
this.pipelineServiceClientConfiguration = pipelineServiceClientConfiguration;
|
this.pipelineServiceClientConfiguration = pipelineServiceClientConfiguration;
|
||||||
|
this.authenticationConfiguration = authenticationConfiguration;
|
||||||
this.dbPackageName = connectionType == ConnectionType.MYSQL ? "mysql" : "postgres";
|
this.dbPackageName = connectionType == ConnectionType.MYSQL ? "mysql" : "postgres";
|
||||||
versionNumbers = convertToNumber(version);
|
versionNumbers = convertToNumber(version);
|
||||||
schemaChanges = new ArrayList<>();
|
schemaChanges = new ArrayList<>();
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
package org.openmetadata.service.migration.utils.v155;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jdbi.v3.core.Handle;
|
||||||
|
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
|
||||||
|
import org.openmetadata.schema.entity.teams.User;
|
||||||
|
import org.openmetadata.schema.services.connections.metadata.AuthProvider;
|
||||||
|
import org.openmetadata.schema.utils.EntityInterfaceUtil;
|
||||||
|
import org.openmetadata.service.jdbi3.CollectionDAO;
|
||||||
|
import org.openmetadata.service.util.JsonUtils;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class MigrationUtil {
|
||||||
|
public static void updateUserNameToEmailPrefixForLdapAuthProvider(
|
||||||
|
Handle handle,
|
||||||
|
CollectionDAO daoCollection,
|
||||||
|
AuthenticationConfiguration config,
|
||||||
|
boolean postgres) {
|
||||||
|
if (config.getProvider().equals(AuthProvider.LDAP)) {
|
||||||
|
LOG.info("Starting migration username -> email prefix");
|
||||||
|
int total = daoCollection.userDAO().listTotalCount();
|
||||||
|
int offset = 0;
|
||||||
|
int limit = 200;
|
||||||
|
while (offset < total) {
|
||||||
|
List<String> userEntities = daoCollection.userDAO().listAfterWithOffset(limit, offset);
|
||||||
|
for (String json : userEntities) {
|
||||||
|
User userEntity = JsonUtils.readValue(json, User.class);
|
||||||
|
String email = userEntity.getEmail();
|
||||||
|
String emailPrefix = email.substring(0, email.indexOf("@"));
|
||||||
|
userEntity.setFullyQualifiedName(EntityInterfaceUtil.quoteName(emailPrefix));
|
||||||
|
userEntity.setName(emailPrefix);
|
||||||
|
|
||||||
|
daoCollection.userDAO().update(userEntity);
|
||||||
|
}
|
||||||
|
offset = offset + limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUserEntityNameHash(handle, postgres);
|
||||||
|
LOG.info("Completed migrating username -> email prefix");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateUserEntityNameHash(Handle handle, boolean postgres) {
|
||||||
|
String updateNameHashSql;
|
||||||
|
if (postgres) {
|
||||||
|
updateNameHashSql = "UPDATE user_entity SET nameHash = MD5(json ->> 'fullyQualifiedName');";
|
||||||
|
} else {
|
||||||
|
updateNameHashSql =
|
||||||
|
"UPDATE user_entity SET nameHash = MD5(JSON_UNQUOTE(JSON_EXTRACT(json, '$.fullyQualifiedName')));";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
handle.execute(updateNameHashSql);
|
||||||
|
LOG.info("Successfully updated nameHash for all user entities.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Error updating nameHash field", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,13 +33,13 @@ public interface AuthenticatorHandler {
|
|||||||
|
|
||||||
void checkIfLoginBlocked(String userName);
|
void checkIfLoginBlocked(String userName);
|
||||||
|
|
||||||
void recordFailedLoginAttempt(String providedIdentity, User user)
|
void recordFailedLoginAttempt(String email, String userName)
|
||||||
throws TemplateException, IOException;
|
throws TemplateException, IOException;
|
||||||
|
|
||||||
void validatePassword(String providedIdentity, User storedUser, String reqPassword)
|
void validatePassword(String providedIdentity, String reqPassword, User omUser)
|
||||||
throws TemplateException, IOException;
|
throws TemplateException, IOException;
|
||||||
|
|
||||||
User lookUserInProvider(String userName);
|
User lookUserInProvider(String email, String pwd) throws TemplateException, IOException;
|
||||||
|
|
||||||
default User registerUser(RegistrationRequest registrationRequest) {
|
default User registerUser(RegistrationRequest registrationRequest) {
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
|
@ -261,7 +261,8 @@ public class BasicAuthenticator implements AuthenticatorHandler {
|
|||||||
|
|
||||||
// Update user about Password Change
|
// Update user about Password Change
|
||||||
try {
|
try {
|
||||||
sendAccountStatus(storedUser, "Update Password", "Change Successful");
|
sendAccountStatus(
|
||||||
|
storedUser.getName(), storedUser.getEmail(), "Update Password", "Change Successful");
|
||||||
} catch (TemplateException ex) {
|
} catch (TemplateException ex) {
|
||||||
LOG.error("Error in sending Password Change Mail to User. Reason : " + ex.getMessage(), ex);
|
LOG.error("Error in sending Password Change Mail to User. Reason : " + ex.getMessage(), ex);
|
||||||
throw new CustomExceptionMessage(424, FAILED_SEND_EMAIL, EMAIL_SENDING_ISSUE);
|
throw new CustomExceptionMessage(424, FAILED_SEND_EMAIL, EMAIL_SENDING_ISSUE);
|
||||||
@ -466,28 +467,29 @@ public class BasicAuthenticator implements AuthenticatorHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtResponse loginUser(LoginRequest loginRequest) throws IOException, TemplateException {
|
public JwtResponse loginUser(LoginRequest loginRequest) throws IOException, TemplateException {
|
||||||
String userName = loginRequest.getEmail();
|
String email = loginRequest.getEmail();
|
||||||
checkIfLoginBlocked(userName);
|
checkIfLoginBlocked(email);
|
||||||
User storedUser = lookUserInProvider(userName);
|
User storedUser = lookUserInProvider(email, loginRequest.getPassword());
|
||||||
validatePassword(userName, storedUser, loginRequest.getPassword());
|
validatePassword(email, loginRequest.getPassword(), storedUser);
|
||||||
return getJwtResponse(storedUser, SecurityUtil.getLoginConfiguration().getJwtTokenExpiryTime());
|
return getJwtResponse(storedUser, SecurityUtil.getLoginConfiguration().getJwtTokenExpiryTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkIfLoginBlocked(String userName) {
|
public void checkIfLoginBlocked(String email) {
|
||||||
if (loginAttemptCache.isLoginBlocked(userName)) {
|
if (loginAttemptCache.isLoginBlocked(email)) {
|
||||||
throw new AuthenticationException(MAX_FAILED_LOGIN_ATTEMPT);
|
throw new AuthenticationException(MAX_FAILED_LOGIN_ATTEMPT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordFailedLoginAttempt(String providedIdentity, User storedUser)
|
public void recordFailedLoginAttempt(String email, String userName)
|
||||||
throws TemplateException, IOException {
|
throws TemplateException, IOException {
|
||||||
loginAttemptCache.recordFailedLogin(providedIdentity);
|
loginAttemptCache.recordFailedLogin(email);
|
||||||
int failedLoginAttempt = loginAttemptCache.getUserFailedLoginCount(providedIdentity);
|
int failedLoginAttempt = loginAttemptCache.getUserFailedLoginCount(email);
|
||||||
if (failedLoginAttempt == SecurityUtil.getLoginConfiguration().getMaxLoginFailAttempts()) {
|
if (failedLoginAttempt == SecurityUtil.getLoginConfiguration().getMaxLoginFailAttempts()) {
|
||||||
sendAccountStatus(
|
sendAccountStatus(
|
||||||
storedUser,
|
userName,
|
||||||
|
email,
|
||||||
"Multiple Failed Login Attempts.",
|
"Multiple Failed Login Attempts.",
|
||||||
String.format(
|
String.format(
|
||||||
"Someone is trying to access your account. Login is Blocked for %s minutes. Please change your password.",
|
"Someone is trying to access your account. Login is Blocked for %s minutes. Please change your password.",
|
||||||
@ -495,35 +497,35 @@ public class BasicAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validatePassword(String providedIdentity, User storedUser, String reqPassword)
|
public void validatePassword(String providedIdentity, String reqPassword, User omUser)
|
||||||
throws TemplateException, IOException {
|
throws TemplateException, IOException {
|
||||||
// when basic auth is enabled and the user is created through the API without password, the
|
// when basic auth is enabled and the user is created through the API without password, the
|
||||||
// stored auth mechanism
|
// stored auth mechanism
|
||||||
// for the user is null
|
// for the user is null
|
||||||
if (storedUser.getAuthenticationMechanism() == null) {
|
if (omUser.getAuthenticationMechanism() == null) {
|
||||||
throw new AuthenticationException(INVALID_USERNAME_PASSWORD);
|
throw new AuthenticationException(INVALID_USERNAME_PASSWORD);
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
LinkedHashMap<String, String> storedData =
|
LinkedHashMap<String, String> storedData =
|
||||||
(LinkedHashMap<String, String>) storedUser.getAuthenticationMechanism().getConfig();
|
(LinkedHashMap<String, String>) omUser.getAuthenticationMechanism().getConfig();
|
||||||
String storedHashPassword = storedData.get("password");
|
String storedHashPassword = storedData.get("password");
|
||||||
if (!BCrypt.verifyer().verify(reqPassword.toCharArray(), storedHashPassword).verified) {
|
if (!BCrypt.verifyer().verify(reqPassword.toCharArray(), storedHashPassword).verified) {
|
||||||
// record Failed Login Attempts
|
// record Failed Login Attempts
|
||||||
recordFailedLoginAttempt(providedIdentity, storedUser);
|
recordFailedLoginAttempt(omUser.getEmail(), omUser.getName());
|
||||||
throw new AuthenticationException(INVALID_USERNAME_PASSWORD);
|
throw new AuthenticationException(INVALID_USERNAME_PASSWORD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User lookUserInProvider(String userName) {
|
public User lookUserInProvider(String email, String pwd) {
|
||||||
User storedUser = null;
|
User storedUser = null;
|
||||||
try {
|
try {
|
||||||
if (userName.contains("@")) {
|
if (email.contains("@")) {
|
||||||
// lookup by User Email
|
// lookup by User Email
|
||||||
storedUser =
|
storedUser =
|
||||||
userRepository.getByEmail(
|
userRepository.getByEmail(
|
||||||
null,
|
null,
|
||||||
userName,
|
email,
|
||||||
new EntityUtil.Fields(
|
new EntityUtil.Fields(
|
||||||
Set.of(USER_PROTECTED_FIELDS, "roles"), "authenticationMechanism,roles"));
|
Set.of(USER_PROTECTED_FIELDS, "roles"), "authenticationMechanism,roles"));
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import static org.openmetadata.service.exception.CatalogExceptionMessage.LDAP_MI
|
|||||||
import static org.openmetadata.service.exception.CatalogExceptionMessage.MAX_FAILED_LOGIN_ATTEMPT;
|
import static org.openmetadata.service.exception.CatalogExceptionMessage.MAX_FAILED_LOGIN_ATTEMPT;
|
||||||
import static org.openmetadata.service.exception.CatalogExceptionMessage.MULTIPLE_EMAIL_ENTRIES;
|
import static org.openmetadata.service.exception.CatalogExceptionMessage.MULTIPLE_EMAIL_ENTRIES;
|
||||||
import static org.openmetadata.service.exception.CatalogExceptionMessage.PASSWORD_RESET_TOKEN_EXPIRED;
|
import static org.openmetadata.service.exception.CatalogExceptionMessage.PASSWORD_RESET_TOKEN_EXPIRED;
|
||||||
|
import static org.openmetadata.service.exception.CatalogExceptionMessage.SELF_SIGNUP_DISABLED_MESSAGE;
|
||||||
|
import static org.openmetadata.service.exception.CatalogExceptionMessage.SELF_SIGNUP_NOT_ENABLED;
|
||||||
import static org.openmetadata.service.util.UserUtil.getRoleListFromUser;
|
import static org.openmetadata.service.util.UserUtil.getRoleListFromUser;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
@ -85,6 +87,7 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
private LoginAttemptCache loginAttemptCache;
|
private LoginAttemptCache loginAttemptCache;
|
||||||
private LdapConfiguration ldapConfiguration;
|
private LdapConfiguration ldapConfiguration;
|
||||||
private LDAPConnectionPool ldapLookupConnectionPool;
|
private LDAPConnectionPool ldapLookupConnectionPool;
|
||||||
|
private boolean isSelfSignUpEnabled;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(OpenMetadataApplicationConfig config) {
|
public void init(OpenMetadataApplicationConfig config) {
|
||||||
@ -100,6 +103,7 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
this.tokenRepository = Entity.getTokenRepository();
|
this.tokenRepository = Entity.getTokenRepository();
|
||||||
this.ldapConfiguration = config.getAuthenticationConfiguration().getLdapConfiguration();
|
this.ldapConfiguration = config.getAuthenticationConfiguration().getLdapConfiguration();
|
||||||
this.loginAttemptCache = new LoginAttemptCache();
|
this.loginAttemptCache = new LoginAttemptCache();
|
||||||
|
this.isSelfSignUpEnabled = config.getAuthenticationConfiguration().getEnableSelfSignup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LDAPConnectionPool getLdapConnectionPool(LdapConfiguration ldapConfiguration) {
|
private LDAPConnectionPool getLdapConnectionPool(LdapConfiguration ldapConfiguration) {
|
||||||
@ -138,10 +142,9 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtResponse loginUser(LoginRequest loginRequest) throws IOException, TemplateException {
|
public JwtResponse loginUser(LoginRequest loginRequest) throws IOException, TemplateException {
|
||||||
checkIfLoginBlocked(loginRequest.getEmail());
|
String email = loginRequest.getEmail();
|
||||||
User storedUser = lookUserInProvider(loginRequest.getEmail());
|
checkIfLoginBlocked(email);
|
||||||
validatePassword(storedUser.getEmail(), storedUser, loginRequest.getPassword());
|
User omUser = lookUserInProvider(email, loginRequest.getPassword());
|
||||||
User omUser = checkAndCreateUser(storedUser.getEmail(), storedUser.getName());
|
|
||||||
return getJwtResponse(omUser, SecurityUtil.getLoginConfiguration().getJwtTokenExpiryTime());
|
return getJwtResponse(omUser, SecurityUtil.getLoginConfiguration().getJwtTokenExpiryTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,21 +152,25 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
* Check if the user exists in database by userName, if user exist, reassign roles for user according to it's ldap
|
* Check if the user exists in database by userName, if user exist, reassign roles for user according to it's ldap
|
||||||
* group else, create a new user and assign roles according to it's ldap group
|
* group else, create a new user and assign roles according to it's ldap group
|
||||||
*
|
*
|
||||||
* @param email email address of user
|
* @param userDn userDn from LDAP
|
||||||
* @param name userName of user
|
* @param email Email of the User
|
||||||
* @return user info
|
* @return user info
|
||||||
* @author Eric Wen@2023-07-16 17:06:43
|
* @author Eric Wen@2023-07-16 17:06:43
|
||||||
*/
|
*/
|
||||||
private User checkAndCreateUser(String email, String name) throws IOException {
|
private User checkAndCreateUser(String userDn, String email, String userName) throws IOException {
|
||||||
// Check if the user exists in OM Database
|
// Check if the user exists in OM Database
|
||||||
try {
|
try {
|
||||||
User omUser =
|
User omUser =
|
||||||
userRepository.getByName(null, name, userRepository.getFields("id,name,email,roles"));
|
userRepository.getByEmail(null, email, userRepository.getFields("id,name,email,roles"));
|
||||||
getRoleForLdap(omUser, Boolean.TRUE);
|
getRoleForLdap(userDn, omUser, Boolean.TRUE);
|
||||||
return omUser;
|
return omUser;
|
||||||
} catch (EntityNotFoundException ex) {
|
} catch (EntityNotFoundException ex) {
|
||||||
// User does not exist
|
if (isSelfSignUpEnabled) {
|
||||||
return userRepository.create(null, getUserForLdap(email, name));
|
return userRepository.create(null, getUserForLdap(userDn, email, userName));
|
||||||
|
} else {
|
||||||
|
throw new CustomExceptionMessage(
|
||||||
|
INTERNAL_SERVER_ERROR, SELF_SIGNUP_NOT_ENABLED, SELF_SIGNUP_DISABLED_MESSAGE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,13 +182,14 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordFailedLoginAttempt(String providedIdentity, User storedUser)
|
public void recordFailedLoginAttempt(String email, String userName)
|
||||||
throws TemplateException, IOException {
|
throws TemplateException, IOException {
|
||||||
loginAttemptCache.recordFailedLogin(providedIdentity);
|
loginAttemptCache.recordFailedLogin(email);
|
||||||
int failedLoginAttempt = loginAttemptCache.getUserFailedLoginCount(providedIdentity);
|
int failedLoginAttempt = loginAttemptCache.getUserFailedLoginCount(email);
|
||||||
if (failedLoginAttempt == SecurityUtil.getLoginConfiguration().getMaxLoginFailAttempts()) {
|
if (failedLoginAttempt == SecurityUtil.getLoginConfiguration().getMaxLoginFailAttempts()) {
|
||||||
EmailUtil.sendAccountStatus(
|
EmailUtil.sendAccountStatus(
|
||||||
storedUser,
|
userName,
|
||||||
|
email,
|
||||||
"Multiple Failed Login Attempts.",
|
"Multiple Failed Login Attempts.",
|
||||||
String.format(
|
String.format(
|
||||||
"Someone is tried accessing your account. Login is Blocked for %s seconds.",
|
"Someone is tried accessing your account. Login is Blocked for %s seconds.",
|
||||||
@ -190,12 +198,12 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validatePassword(String providedIdentity, User storedUser, String reqPassword)
|
public void validatePassword(String userDn, String reqPassword, User dummy)
|
||||||
throws TemplateException, IOException {
|
throws TemplateException, IOException {
|
||||||
// performed in LDAP , the storedUser's name set as DN of the User in Ldap
|
// performed in LDAP , the storedUser's name set as DN of the User in Ldap
|
||||||
BindResult bindingResult = null;
|
BindResult bindingResult = null;
|
||||||
try {
|
try {
|
||||||
bindingResult = ldapLookupConnectionPool.bind(storedUser.getName(), reqPassword);
|
bindingResult = ldapLookupConnectionPool.bind(userDn, reqPassword);
|
||||||
if (Objects.equals(bindingResult.getResultCode().getName(), ResultCode.SUCCESS.getName())) {
|
if (Objects.equals(bindingResult.getResultCode().getName(), ResultCode.SUCCESS.getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -203,7 +211,7 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
if (bindingResult != null
|
if (bindingResult != null
|
||||||
&& Objects.equals(
|
&& Objects.equals(
|
||||||
bindingResult.getResultCode().getName(), ResultCode.INVALID_CREDENTIALS.getName())) {
|
bindingResult.getResultCode().getName(), ResultCode.INVALID_CREDENTIALS.getName())) {
|
||||||
recordFailedLoginAttempt(providedIdentity, storedUser);
|
recordFailedLoginAttempt(dummy.getEmail(), dummy.getName());
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
UNAUTHORIZED, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
|
UNAUTHORIZED, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
|
||||||
}
|
}
|
||||||
@ -218,7 +226,20 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User lookUserInProvider(String email) {
|
public User lookUserInProvider(String email, String pwd) throws TemplateException, IOException {
|
||||||
|
String userDN = getUserDnFromLdap(email);
|
||||||
|
|
||||||
|
if (!nullOrEmpty(userDN)) {
|
||||||
|
User dummy = getUserForLdap(email);
|
||||||
|
validatePassword(userDN, pwd, dummy);
|
||||||
|
return checkAndCreateUser(userDN, email, dummy.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CustomExceptionMessage(
|
||||||
|
INTERNAL_SERVER_ERROR, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUserDnFromLdap(String email) {
|
||||||
try {
|
try {
|
||||||
Filter emailFilter =
|
Filter emailFilter =
|
||||||
Filter.createEqualityFilter(ldapConfiguration.getMailAttributeName(), email);
|
Filter.createEqualityFilter(ldapConfiguration.getMailAttributeName(), email);
|
||||||
@ -237,8 +258,10 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
Attribute emailAttr =
|
Attribute emailAttr =
|
||||||
searchResultEntry.getAttribute(ldapConfiguration.getMailAttributeName());
|
searchResultEntry.getAttribute(ldapConfiguration.getMailAttributeName());
|
||||||
|
|
||||||
if (!CommonUtil.nullOrEmpty(userDN) && emailAttr != null) {
|
if (!CommonUtil.nullOrEmpty(userDN)
|
||||||
return getUserForLdap(email).withName(userDN.toLowerCase());
|
&& emailAttr != null
|
||||||
|
&& email.equalsIgnoreCase(emailAttr.getValue())) {
|
||||||
|
return userDN;
|
||||||
} else {
|
} else {
|
||||||
throw new CustomExceptionMessage(FORBIDDEN, INVALID_USER_OR_PASSWORD, LDAP_MISSING_ATTR);
|
throw new CustomExceptionMessage(FORBIDDEN, INVALID_USER_OR_PASSWORD, LDAP_MISSING_ATTR);
|
||||||
}
|
}
|
||||||
@ -247,7 +270,7 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES, MULTIPLE_EMAIL_ENTRIES);
|
INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES, MULTIPLE_EMAIL_ENTRIES);
|
||||||
} else {
|
} else {
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES, INVALID_EMAIL_PASSWORD);
|
INTERNAL_SERVER_ERROR, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
|
||||||
}
|
}
|
||||||
} catch (LDAPException ex) {
|
} catch (LDAPException ex) {
|
||||||
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, "LDAP_ERROR", ex.getMessage());
|
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, "LDAP_ERROR", ex.getMessage());
|
||||||
@ -262,14 +285,14 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
.withAuthenticationMechanism(null);
|
.withAuthenticationMechanism(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private User getUserForLdap(String email, String userName) {
|
private User getUserForLdap(String ldapUserDn, String email, String userName) {
|
||||||
User user =
|
User user =
|
||||||
UserUtil.getUser(
|
UserUtil.getUser(
|
||||||
userName, new CreateUser().withName(userName).withEmail(email).withIsBot(false))
|
userName, new CreateUser().withName(userName).withEmail(email).withIsBot(false))
|
||||||
.withIsEmailVerified(false)
|
.withIsEmailVerified(false)
|
||||||
.withAuthenticationMechanism(null);
|
.withAuthenticationMechanism(null);
|
||||||
try {
|
try {
|
||||||
getRoleForLdap(user, false);
|
getRoleForLdap(ldapUserDn, user, false);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
LOG.error(
|
LOG.error(
|
||||||
"Failed to assign roles from LDAP to OpenMetadata for the user {} due to {}",
|
"Failed to assign roles from LDAP to OpenMetadata for the user {} due to {}",
|
||||||
@ -286,7 +309,8 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
* @param reAssign flag to decide whether to reassign roles
|
* @param reAssign flag to decide whether to reassign roles
|
||||||
* @author Eric Wen@2023-07-16 17:23:57
|
* @author Eric Wen@2023-07-16 17:23:57
|
||||||
*/
|
*/
|
||||||
private void getRoleForLdap(User user, Boolean reAssign) throws JsonProcessingException {
|
private void getRoleForLdap(String userDn, User user, Boolean reAssign)
|
||||||
|
throws JsonProcessingException {
|
||||||
// Get user's groups from LDAP server using the DN of the user
|
// Get user's groups from LDAP server using the DN of the user
|
||||||
try {
|
try {
|
||||||
Filter groupFilter =
|
Filter groupFilter =
|
||||||
@ -294,8 +318,7 @@ public class LdapAuthenticator implements AuthenticatorHandler {
|
|||||||
ldapConfiguration.getGroupAttributeName(),
|
ldapConfiguration.getGroupAttributeName(),
|
||||||
ldapConfiguration.getGroupAttributeValue());
|
ldapConfiguration.getGroupAttributeValue());
|
||||||
Filter groupMemberAttr =
|
Filter groupMemberAttr =
|
||||||
Filter.createEqualityFilter(
|
Filter.createEqualityFilter(ldapConfiguration.getGroupMemberAttributeName(), userDn);
|
||||||
ldapConfiguration.getGroupMemberAttributeName(), user.getName());
|
|
||||||
Filter groupAndMemberFilter = Filter.createANDFilter(groupFilter, groupMemberAttr);
|
Filter groupAndMemberFilter = Filter.createANDFilter(groupFilter, groupMemberAttr);
|
||||||
SearchRequest searchRequest =
|
SearchRequest searchRequest =
|
||||||
new SearchRequest(
|
new SearchRequest(
|
||||||
|
@ -33,7 +33,7 @@ public class NoopAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordFailedLoginAttempt(String providedIdentity, User user) {
|
public void recordFailedLoginAttempt(String providedIdentity, String userName) {
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
Response.Status.FORBIDDEN,
|
Response.Status.FORBIDDEN,
|
||||||
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
||||||
@ -41,7 +41,7 @@ public class NoopAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validatePassword(String providedIdentity, User storedUser, String reqPassword) {
|
public void validatePassword(String providedIdentity, String reqPassword, User storedUser) {
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
Response.Status.FORBIDDEN,
|
Response.Status.FORBIDDEN,
|
||||||
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
||||||
@ -49,7 +49,7 @@ public class NoopAuthenticator implements AuthenticatorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User lookUserInProvider(String userName) {
|
public User lookUserInProvider(String email, String pwd) {
|
||||||
throw new CustomExceptionMessage(
|
throw new CustomExceptionMessage(
|
||||||
Response.Status.FORBIDDEN,
|
Response.Status.FORBIDDEN,
|
||||||
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
|
||||||
|
@ -618,6 +618,7 @@ public class OpenMetadataOperations implements Callable<Integer> {
|
|||||||
connType,
|
connType,
|
||||||
extensionSQLScriptRootPath,
|
extensionSQLScriptRootPath,
|
||||||
config.getPipelineServiceClientConfiguration(),
|
config.getPipelineServiceClientConfiguration(),
|
||||||
|
config.getAuthenticationConfiguration(),
|
||||||
force);
|
force);
|
||||||
workflow.loadMigrations();
|
workflow.loadMigrations();
|
||||||
workflow.printMigrationInfo();
|
workflow.printMigrationInfo();
|
||||||
|
@ -121,7 +121,7 @@ public class EmailUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendAccountStatus(User user, String action, String status)
|
public static void sendAccountStatus(String userName, String email, String action, String status)
|
||||||
throws IOException, TemplateException {
|
throws IOException, TemplateException {
|
||||||
|
|
||||||
if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
|
if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
|
||||||
@ -129,7 +129,7 @@ public class EmailUtil {
|
|||||||
new TemplatePopulatorBuilder()
|
new TemplatePopulatorBuilder()
|
||||||
.add(ENTITY, getSmtpSettings().getEmailingEntity())
|
.add(ENTITY, getSmtpSettings().getEmailingEntity())
|
||||||
.add(SUPPORT_URL, getSmtpSettings().getSupportUrl())
|
.add(SUPPORT_URL, getSmtpSettings().getSupportUrl())
|
||||||
.add(USERNAME, user.getName())
|
.add(USERNAME, userName)
|
||||||
.add(ACTION_KEY, action)
|
.add(ACTION_KEY, action)
|
||||||
.add(ACTION_STATUS_KEY, status)
|
.add(ACTION_STATUS_KEY, status)
|
||||||
.build();
|
.build();
|
||||||
@ -137,11 +137,11 @@ public class EmailUtil {
|
|||||||
sendMail(
|
sendMail(
|
||||||
getAccountStatusChangeSubject(),
|
getAccountStatusChangeSubject(),
|
||||||
templatePopulator,
|
templatePopulator,
|
||||||
user.getEmail(),
|
email,
|
||||||
ACCOUNT_ACTIVITY_CHANGE_TEMPLATE,
|
ACCOUNT_ACTIVITY_CHANGE_TEMPLATE,
|
||||||
true);
|
true);
|
||||||
} else {
|
} else {
|
||||||
LOG.warn(EMAIL_IGNORE_MSG, user.getEmail());
|
LOG.warn(EMAIL_IGNORE_MSG, userName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ import org.junit.jupiter.api.BeforeAll;
|
|||||||
import org.junit.jupiter.api.TestInstance;
|
import org.junit.jupiter.api.TestInstance;
|
||||||
import org.openmetadata.common.utils.CommonUtil;
|
import org.openmetadata.common.utils.CommonUtil;
|
||||||
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
|
||||||
|
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
|
||||||
import org.openmetadata.schema.service.configuration.elasticsearch.ElasticSearchConfiguration;
|
import org.openmetadata.schema.service.configuration.elasticsearch.ElasticSearchConfiguration;
|
||||||
import org.openmetadata.schema.type.IndexMappingLanguage;
|
import org.openmetadata.schema.type.IndexMappingLanguage;
|
||||||
import org.openmetadata.service.jdbi3.CollectionDAO;
|
import org.openmetadata.service.jdbi3.CollectionDAO;
|
||||||
@ -208,6 +209,7 @@ public abstract class OpenMetadataApplicationTest {
|
|||||||
nativeMigrationScriptsLocation,
|
nativeMigrationScriptsLocation,
|
||||||
extensionMigrationScripsLocation,
|
extensionMigrationScripsLocation,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
false);
|
false);
|
||||||
createIndices();
|
createIndices();
|
||||||
APP.before();
|
APP.before();
|
||||||
@ -221,6 +223,7 @@ public abstract class OpenMetadataApplicationTest {
|
|||||||
String nativeMigrationSQLPath,
|
String nativeMigrationSQLPath,
|
||||||
String extensionSQLScriptRootPath,
|
String extensionSQLScriptRootPath,
|
||||||
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
PipelineServiceClientConfiguration pipelineServiceClientConfiguration,
|
||||||
|
AuthenticationConfiguration authenticationConfiguration,
|
||||||
boolean forceMigrations) {
|
boolean forceMigrations) {
|
||||||
DatasourceConfig.initialize(connType.label);
|
DatasourceConfig.initialize(connType.label);
|
||||||
MigrationWorkflow workflow =
|
MigrationWorkflow workflow =
|
||||||
@ -230,6 +233,7 @@ public abstract class OpenMetadataApplicationTest {
|
|||||||
connType,
|
connType,
|
||||||
extensionSQLScriptRootPath,
|
extensionSQLScriptRootPath,
|
||||||
pipelineServiceClientConfiguration,
|
pipelineServiceClientConfiguration,
|
||||||
|
authenticationConfiguration,
|
||||||
forceMigrations);
|
forceMigrations);
|
||||||
// Initialize search repository
|
// Initialize search repository
|
||||||
SearchRepository searchRepository =
|
SearchRepository searchRepository =
|
||||||
|
@ -28,7 +28,7 @@ public class MigrationWorkflowTest extends OpenMetadataApplicationTest {
|
|||||||
migrationWorkflow =
|
migrationWorkflow =
|
||||||
spy(
|
spy(
|
||||||
new MigrationWorkflow(
|
new MigrationWorkflow(
|
||||||
jdbi, "nativePath", ConnectionType.MYSQL, "extensionPath", null, false));
|
jdbi, "nativePath", ConnectionType.MYSQL, "extensionPath", null, null, false));
|
||||||
|
|
||||||
omMigrationList =
|
omMigrationList =
|
||||||
List.of(
|
List.of(
|
||||||
@ -37,18 +37,21 @@ public class MigrationWorkflowTest extends OpenMetadataApplicationTest {
|
|||||||
null,
|
null,
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration(),
|
||||||
false),
|
false),
|
||||||
new MigrationFile(
|
new MigrationFile(
|
||||||
new File("/bootstrap/sql/migrations/native/1.2.0"),
|
new File("/bootstrap/sql/migrations/native/1.2.0"),
|
||||||
null,
|
null,
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration(),
|
||||||
false),
|
false),
|
||||||
new MigrationFile(
|
new MigrationFile(
|
||||||
new File("/bootstrap/sql/migrations/native/1.2.1"),
|
new File("/bootstrap/sql/migrations/native/1.2.1"),
|
||||||
null,
|
null,
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration(),
|
||||||
false));
|
false));
|
||||||
|
|
||||||
collateMigrationList =
|
collateMigrationList =
|
||||||
@ -58,12 +61,14 @@ public class MigrationWorkflowTest extends OpenMetadataApplicationTest {
|
|||||||
null,
|
null,
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration(),
|
||||||
true),
|
true),
|
||||||
new MigrationFile(
|
new MigrationFile(
|
||||||
new File("/bootstrap-collate/sql/migrations/native/1.2.2-collate"),
|
new File("/bootstrap-collate/sql/migrations/native/1.2.2-collate"),
|
||||||
null,
|
null,
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration(),
|
||||||
true));
|
true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,18 +77,19 @@ public class MigrationWorkflowTest extends OpenMetadataApplicationTest {
|
|||||||
Mockito.doReturn(omMigrationList)
|
Mockito.doReturn(omMigrationList)
|
||||||
.when(migrationWorkflow)
|
.when(migrationWorkflow)
|
||||||
.getMigrationFilesFromPath(
|
.getMigrationFilesFromPath(
|
||||||
eq("nativePath"), any(ConnectionType.class), eq(null), eq(false));
|
eq("nativePath"), any(ConnectionType.class), eq(null), eq(null), eq(false));
|
||||||
Mockito.doReturn(collateMigrationList)
|
Mockito.doReturn(collateMigrationList)
|
||||||
.when(migrationWorkflow)
|
.when(migrationWorkflow)
|
||||||
.getMigrationFilesFromPath(
|
.getMigrationFilesFromPath(
|
||||||
eq("extensionPath"), any(ConnectionType.class), eq(null), eq(true));
|
eq("extensionPath"), any(ConnectionType.class), eq(null), eq(null), eq(true));
|
||||||
|
|
||||||
List<MigrationFile> foundList =
|
List<MigrationFile> foundList =
|
||||||
migrationWorkflow.getMigrationFiles(
|
migrationWorkflow.getMigrationFiles(
|
||||||
"nativePath",
|
"nativePath",
|
||||||
ConnectionType.MYSQL,
|
ConnectionType.MYSQL,
|
||||||
"extensionPath",
|
"extensionPath",
|
||||||
migrationWorkflow.getPipelineServiceClientConfiguration());
|
migrationWorkflow.getPipelineServiceClientConfiguration(),
|
||||||
|
migrationWorkflow.getAuthenticationConfiguration());
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
List.of("1.1.0", "1.1.0-collate", "1.2.0", "1.2.1", "1.2.2-collate"),
|
List.of("1.1.0", "1.1.0-collate", "1.2.0", "1.2.1", "1.2.2-collate"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user