Fix: Improve error messages (#11244)

This commit is contained in:
Nahuel 2023-04-27 17:45:25 +02:00 committed by GitHub
parent 33c429f67c
commit a4af11fba4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 152 additions and 7 deletions

View File

@ -62,6 +62,10 @@ public abstract class SecretsManager {
return encryptOrDecryptPasswordFields(
newConnectionConfig, buildSecretId(true, serviceType.value(), connectionName), encrypt, true);
} catch (Exception e) {
String message = SecretsUtil.buildExceptionMessageConnection(e.getMessage(), connectionType, encrypt);
if (message != null) {
throw new InvalidServiceConnectionException(message);
}
throw InvalidServiceConnectionException.byMessage(
connectionType, String.format("Failed to encrypt connection instance of %s", connectionType));
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openmetadata.service.secrets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SecretsUtil {
/**
* Returns an error message when it is related to an Unrecognized field
*
* @param message the message to be formatted if the Unrecognized field is between quotes
* @param defaultMessage default message to be formatted if the Unrecognized field is not between quotes
* @param exceptionMessage the exception message
* @param type the type of error
* @return null if the message does not contain 'Unrecognized field' in the exception message
*/
public static String buildExceptionMessageUnrecognizedField(
String message, String defaultMessage, String exceptionMessage, String type) {
if (exceptionMessage != null && exceptionMessage.contains("Unrecognized field")) {
Pattern pattern = Pattern.compile("Unrecognized field \"(.*?)\"");
Matcher matcher = pattern.matcher(exceptionMessage);
if (matcher.find()) {
String fieldValue = matcher.group(1);
return String.format(message, type, fieldValue);
}
return String.format(defaultMessage, type);
}
return null;
}
public static String buildExceptionMessageConnection(
String exceptionMessage, String type, String firstAction, String secondAction, boolean isFirstAction) {
return buildExceptionMessageUnrecognizedField(
"Failed to "
+ (isFirstAction ? firstAction : secondAction)
+ " '%s' connection stored in DB due to an unrecognized field: '%s'",
"Failed to "
+ (isFirstAction ? firstAction : secondAction)
+ " '%s' connection stored in DB due to malformed connection object.",
exceptionMessage,
type);
}
public static String buildExceptionMessageConnection(String exceptionMessage, String type, boolean encrypt) {
return buildExceptionMessageConnection(exceptionMessage, type, "encrypt", "decrypt", encrypt);
}
public static String buildExceptionMessageConnectionMask(String exceptionMessage, String type, boolean mask) {
return buildExceptionMessageConnection(exceptionMessage, type, "mask", "unmask", mask);
}
}

View File

@ -24,6 +24,7 @@ import org.openmetadata.schema.entity.services.ingestionPipelines.IngestionPipel
import org.openmetadata.schema.entity.teams.AuthenticationMechanism;
import org.openmetadata.service.exception.EntityMaskException;
import org.openmetadata.service.fernet.Fernet;
import org.openmetadata.service.secrets.SecretsUtil;
import org.openmetadata.service.secrets.converter.ClassConverterFactory;
import org.openmetadata.service.util.AuthenticationMechanismBuilder;
import org.openmetadata.service.util.IngestionPipelineBuilder;
@ -54,6 +55,10 @@ public class PasswordEntityMasker extends EntityMasker {
maskPasswordFields(convertedConnectionConfig);
return convertedConnectionConfig;
} catch (Exception e) {
String message = SecretsUtil.buildExceptionMessageConnectionMask(e.getMessage(), connectionType, true);
if (message != null) {
throw new EntityMaskException(message);
}
throw new EntityMaskException(String.format("Failed to mask connection instance of %s", connectionType));
}
}
@ -109,6 +114,10 @@ public class PasswordEntityMasker extends EntityMasker {
unmaskPasswordFields(toUnmaskConfig, NEW_KEY, passwordsMap);
return toUnmaskConfig;
} catch (Exception e) {
String message = SecretsUtil.buildExceptionMessageConnectionMask(e.getMessage(), connectionType, false);
if (message != null) {
throw new EntityMaskException(message);
}
throw new EntityMaskException(String.format("Failed to unmask connection instance of %s", connectionType));
}
}

View File

@ -15,6 +15,7 @@ package org.openmetadata.service.secrets;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -41,6 +42,7 @@ import org.openmetadata.schema.security.secrets.SecretsManagerProvider;
import org.openmetadata.schema.services.connections.database.MysqlConnection;
import org.openmetadata.schema.services.connections.metadata.OpenMetadataConnection;
import org.openmetadata.service.Entity;
import org.openmetadata.service.exception.InvalidServiceConnectionException;
import org.openmetadata.service.fernet.Fernet;
import org.openmetadata.service.util.JsonUtils;
@ -105,6 +107,34 @@ public abstract class ExternalSecretsManagerTest {
testEncryptWorkflowObject(ENCRYPT);
}
@Test
void testExceptionConnection() {
CreateDatabaseService.DatabaseServiceType databaseServiceType = CreateDatabaseService.DatabaseServiceType.Mysql;
String connectionName = "test";
Map<String, String> mysqlConnection = Map.of("password", "openmetadata-test", "username1", "openmetadata-test");
InvalidServiceConnectionException thrown =
Assertions.assertThrows(
InvalidServiceConnectionException.class,
() ->
secretsManager.encryptOrDecryptServiceConnectionConfig(
mysqlConnection, databaseServiceType.value(), connectionName, ServiceType.DATABASE, true));
Assertions.assertEquals(
"Failed to encrypt 'Mysql' connection stored in DB due to an unrecognized field: 'username1'",
thrown.getMessage());
thrown =
Assertions.assertThrows(
InvalidServiceConnectionException.class,
() ->
secretsManager.encryptOrDecryptServiceConnectionConfig(
mysqlConnection, databaseServiceType.value(), connectionName, ServiceType.DATABASE, false));
Assertions.assertEquals(
"Failed to decrypt 'Mysql' connection stored in DB due to an unrecognized field: 'username1'",
thrown.getMessage());
}
@Test
void testReturnsExpectedSecretManagerProvider() {
assertEquals(expectedSecretManagerProvider(), secretsManager.getSecretsManagerProvider());

View File

@ -1,5 +1,12 @@
package org.openmetadata.service.secrets.masker;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openmetadata.schema.entity.services.ServiceType;
import org.openmetadata.schema.services.connections.database.MysqlConnection;
import org.openmetadata.service.exception.EntityMaskException;
public class PasswordEntityMaskerTest extends TestEntityMasker {
public PasswordEntityMaskerTest() {
CONFIG.setMaskPasswordsAPI(true);
@ -9,4 +16,35 @@ public class PasswordEntityMaskerTest extends TestEntityMasker {
protected String getMaskedPassword() {
return PasswordEntityMasker.PASSWORD_MASK;
}
@Test
void testExceptionConnection() {
Map<String, String> mysqlConnectionObject =
Map.of("password", "openmetadata-test", "username1", "openmetadata-test");
EntityMaskException thrown =
Assertions.assertThrows(
EntityMaskException.class,
() -> {
EntityMaskerFactory.createEntityMasker(CONFIG)
.maskServiceConnectionConfig(mysqlConnectionObject, "Mysql", ServiceType.DATABASE);
});
Assertions.assertEquals(
"Failed to mask 'Mysql' connection stored in DB due to an unrecognized field: 'username1'",
thrown.getMessage());
thrown =
Assertions.assertThrows(
EntityMaskException.class,
() -> {
EntityMaskerFactory.createEntityMasker(CONFIG)
.unmaskServiceConnectionConfig(
mysqlConnectionObject, new MysqlConnection(), "Mysql", ServiceType.DATABASE);
});
Assertions.assertEquals(
"Failed to unmask 'Mysql' connection stored in DB due to an unrecognized field: 'username1'",
thrown.getMessage());
}
}

View File

@ -1,6 +1,6 @@
# Metadata
DatabaseService Metadata Pipeline Configuration.
Database Service Metadata Pipeline Configuration.
## Configuration