This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 1fd222590 [#5520] improvement(JDBC-connection): handle JDBC access 
denied exception (#5546)
1fd222590 is described below

commit 1fd2225901680f8200066adb3532a8110360ebca
Author: mchades <[email protected]>
AuthorDate: Wed Nov 27 14:14:25 2024 +0800

    [#5520] improvement(JDBC-connection): handle JDBC access denied exception 
(#5546)
    
    ### What changes were proposed in this pull request?
    
    catch JDBC access denied exception and convert to UnauthorizedException
    
    ### Why are the changes needed?
    
    The REST client need the real exception instead of
    GravitinoRuntimeException
    
    Fix: #5520
    
    ### Does this PR introduce _any_ user-facing change?
    
    no
    
    ### How was this patch tested?
    
    ITs added
---
 .../catalog/jdbc/JdbcCatalogOperations.java        | 15 +++--------
 .../MySQLProtocolCompatibleCatalogOperations.java  |  3 +--
 .../jdbc/converter/JdbcExceptionConverter.java     |  5 ++++
 .../doris/converter/DorisExceptionConverter.java   |  4 +++
 .../doris/integration/test/CatalogDorisIT.java     | 25 ++++++++++++++++++-
 .../mysql/integration/test/CatalogMysqlIT.java     | 29 ++++++++++++++++++++++
 .../integration/test/CatalogOceanBaseIT.java       | 29 ++++++++++++++++++++++
 .../converter/PostgreSqlExceptionConverter.java    |  4 +++
 .../integration/test/CatalogPostgreSqlIT.java      | 27 ++++++++++++++++++++
 .../integration/test/TestMultipleJDBCLoad.java     | 19 +++++++++++++-
 .../lakehouse/paimon/utils/CatalogUtils.java       | 13 +++++++++-
 .../integration/test/CatalogPaimonBaseIT.java      |  4 +--
 .../integration/test/CatalogPaimonJdbcIT.java      | 23 +++++++++++++++++
 .../gravitino/dto/responses/ErrorResponse.java     |  4 +--
 .../iceberg/common/utils/IcebergCatalogUtil.java   | 14 ++++++++++-
 15 files changed, 196 insertions(+), 22 deletions(-)

diff --git 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
index aef5ecac3..56490d475 100644
--- 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
+++ 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
@@ -56,7 +56,6 @@ import org.apache.gravitino.connector.CatalogInfo;
 import org.apache.gravitino.connector.CatalogOperations;
 import org.apache.gravitino.connector.HasPropertyMetadata;
 import org.apache.gravitino.connector.SupportsSchemas;
-import org.apache.gravitino.exceptions.GravitinoRuntimeException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NoSuchTableException;
@@ -521,20 +520,12 @@ public class JdbcCatalogOperations implements 
CatalogOperations, SupportsSchemas
           metaData.getDriverMajorVersion(),
           metaData.getDriverMinorVersion());
     } catch (final SQLException se) {
-      throw new GravitinoRuntimeException(
-          se, "Failed to get JDBC driver information %s: ", se.getMessage());
+      throw exceptionConverter.toGravitinoException(se);
     }
   }
 
-  /**
-   * Check the version of JDBC driver can supported.
-   *
-   * @return Returns the result of checking the jdbc driver version. If 
success return true,
-   *     otherwise throw a RuntimeException
-   */
-  public boolean checkJDBCDriverVersion() {
-    return true;
-  }
+  /** Check if the JDBC driver version is supported. If not, throw an 
exception. */
+  public void checkJDBCDriverVersion() {}
 
   private Table internalAlterTable(NameIdentifier tableIdent, TableChange... 
changes)
       throws NoSuchTableException, IllegalArgumentException {
diff --git 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
index 35f3a659c..b4ee565dc 100644
--- 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
+++ 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
@@ -50,7 +50,7 @@ public class MySQLProtocolCompatibleCatalogOperations extends 
JdbcCatalogOperati
   }
 
   @Override
-  public boolean checkJDBCDriverVersion() {
+  public void checkJDBCDriverVersion() {
     JDBCDriverInfo driverInfo = getDiverInfo();
     if (driverInfo.majorVersion < MYSQL_JDBC_DRIVER_MINIMAL_SUPPORT_VERSION) {
       throw new RuntimeException(
@@ -58,7 +58,6 @@ public class MySQLProtocolCompatibleCatalogOperations extends 
JdbcCatalogOperati
               "Mysql catalog does not support the jdbc driver version %s, 
minimal required version is 8.0",
               driverInfo.version));
     }
-    return true;
   }
 
   @Override
diff --git 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcExceptionConverter.java
 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcExceptionConverter.java
index 716cfc28d..d4a60c8db 100644
--- 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcExceptionConverter.java
+++ 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcExceptionConverter.java
@@ -19,6 +19,7 @@
 package org.apache.gravitino.catalog.jdbc.converter;
 
 import java.sql.SQLException;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.GravitinoRuntimeException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NoSuchTableException;
@@ -51,6 +52,10 @@ public class JdbcExceptionConverter {
       case 1051:
         return new NoSuchTableException(sqlException, 
sqlException.getMessage());
       default:
+        if (sqlException.getMessage() != null
+            && sqlException.getMessage().contains("Access denied")) {
+          return new ConnectionFailedException(sqlException, 
sqlException.getMessage());
+        }
         return new GravitinoRuntimeException(sqlException, 
sqlException.getMessage());
     }
   }
diff --git 
a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/converter/DorisExceptionConverter.java
 
b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/converter/DorisExceptionConverter.java
index 9c1cc11a2..ccdd4c7da 100644
--- 
a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/converter/DorisExceptionConverter.java
+++ 
b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/converter/DorisExceptionConverter.java
@@ -22,6 +22,7 @@ import com.google.common.annotations.VisibleForTesting;
 import java.sql.SQLException;
 import java.util.regex.Pattern;
 import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.GravitinoRuntimeException;
 import org.apache.gravitino.exceptions.NoSuchColumnException;
 import org.apache.gravitino.exceptions.NoSuchPartitionException;
@@ -109,6 +110,9 @@ public class DorisExceptionConverter extends 
JdbcExceptionConverter {
       case CODE_PARTITION_ALREADY_EXISTS:
         return new PartitionAlreadyExistsException(se, se.getMessage());
       default:
+        if (se.getMessage() != null && se.getMessage().contains("Access 
denied")) {
+          return new ConnectionFailedException(se, se.getMessage());
+        }
         return new GravitinoRuntimeException(se, se.getMessage());
     }
   }
diff --git 
a/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/integration/test/CatalogDorisIT.java
 
b/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/integration/test/CatalogDorisIT.java
index 96b92b696..ca04c03c4 100644
--- 
a/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/integration/test/CatalogDorisIT.java
+++ 
b/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/integration/test/CatalogDorisIT.java
@@ -42,6 +42,7 @@ import org.apache.gravitino.Schema;
 import org.apache.gravitino.SupportsSchemas;
 import org.apache.gravitino.catalog.jdbc.config.JdbcConfig;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.NoSuchPartitionException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.SchemaAlreadyExistsException;
@@ -110,6 +111,7 @@ public class CatalogDorisIT extends BaseIT {
 
   private static final ContainerSuite containerSuite = 
ContainerSuite.getInstance();
   private GravitinoMetalake metalake;
+  private String jdbcUrl;
 
   protected Catalog catalog;
 
@@ -155,7 +157,7 @@ public class CatalogDorisIT extends BaseIT {
 
     DorisContainer dorisContainer = containerSuite.getDorisContainer();
 
-    String jdbcUrl =
+    jdbcUrl =
         String.format(
             "jdbc:mysql://%s:%d/",
             dorisContainer.getContainerIpAddress(), 
DorisContainer.FE_MYSQL_PORT);
@@ -462,6 +464,27 @@ public class CatalogDorisIT extends BaseIT {
         IllegalArgumentException.class, () -> 
catalog.asTableCatalog().dropTable(tableIdentifier4));
   }
 
+  @Test
+  void testTestConnection() {
+    Map<String, String> catalogProperties = Maps.newHashMap();
+    catalogProperties.put(JdbcConfig.JDBC_URL.getKey(), jdbcUrl);
+    catalogProperties.put(JdbcConfig.JDBC_DRIVER.getKey(), DRIVER_CLASS_NAME);
+    catalogProperties.put(JdbcConfig.USERNAME.getKey(), 
DorisContainer.USER_NAME);
+    catalogProperties.put(JdbcConfig.PASSWORD.getKey(), "wrong_password");
+
+    Exception exception =
+        assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    GravitinoITUtils.genRandomName("doris_it_catalog"),
+                    Catalog.Type.RELATIONAL,
+                    provider,
+                    "doris catalog comment",
+                    catalogProperties));
+    Assertions.assertTrue(exception.getMessage().contains("Access denied for 
user"));
+  }
+
   @Test
   void testAlterDorisTable() {
     // create a table
diff --git 
a/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
index 4d4237d72..6b8c824d0 100644
--- 
a/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
+++ 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
@@ -45,6 +45,7 @@ import org.apache.gravitino.auth.AuthConstants;
 import org.apache.gravitino.catalog.jdbc.config.JdbcConfig;
 import 
org.apache.gravitino.catalog.mysql.integration.test.service.MysqlService;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NotFoundException;
 import org.apache.gravitino.exceptions.SchemaAlreadyExistsException;
@@ -256,6 +257,34 @@ public class CatalogMysqlIT extends BaseIT {
     return properties;
   }
 
+  @Test
+  void testTestConnection() throws SQLException {
+    Map<String, String> catalogProperties = Maps.newHashMap();
+
+    catalogProperties.put(
+        JdbcConfig.JDBC_URL.getKey(),
+        StringUtils.substring(
+            MYSQL_CONTAINER.getJdbcUrl(TEST_DB_NAME),
+            0,
+            MYSQL_CONTAINER.getJdbcUrl(TEST_DB_NAME).lastIndexOf("/")));
+    catalogProperties.put(
+        JdbcConfig.JDBC_DRIVER.getKey(), 
MYSQL_CONTAINER.getDriverClassName(TEST_DB_NAME));
+    catalogProperties.put(JdbcConfig.USERNAME.getKey(), 
MYSQL_CONTAINER.getUsername());
+    catalogProperties.put(JdbcConfig.PASSWORD.getKey(), "wrong_password");
+
+    Exception exception =
+        assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    GravitinoITUtils.genRandomName("mysql_it_catalog"),
+                    Catalog.Type.RELATIONAL,
+                    provider,
+                    "comment",
+                    catalogProperties));
+    Assertions.assertTrue(exception.getMessage().contains("Access denied for 
user"));
+  }
+
   @Test
   void testOperationMysqlSchema() {
     SupportsSchemas schemas = catalog.asSchemas();
diff --git 
a/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/integration/test/CatalogOceanBaseIT.java
 
b/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/integration/test/CatalogOceanBaseIT.java
index edcc9354b..4b5181c74 100644
--- 
a/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/integration/test/CatalogOceanBaseIT.java
+++ 
b/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/integration/test/CatalogOceanBaseIT.java
@@ -43,6 +43,7 @@ import org.apache.gravitino.auth.AuthConstants;
 import org.apache.gravitino.catalog.jdbc.config.JdbcConfig;
 import 
org.apache.gravitino.catalog.oceanbase.integration.test.service.OceanBaseService;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NotFoundException;
 import org.apache.gravitino.exceptions.SchemaAlreadyExistsException;
@@ -322,6 +323,34 @@ public class CatalogOceanBaseIT extends BaseIT {
     Assertions.assertTrue(schemaNames.contains(schemaName));
   }
 
+  @Test
+  void testTestConnection() throws SQLException {
+    Map<String, String> catalogProperties = Maps.newHashMap();
+
+    catalogProperties.put(
+        JdbcConfig.JDBC_URL.getKey(),
+        StringUtils.substring(
+            OCEANBASE_CONTAINER.getJdbcUrl(TEST_DB_NAME),
+            0,
+            OCEANBASE_CONTAINER.getJdbcUrl(TEST_DB_NAME).lastIndexOf("/")));
+    catalogProperties.put(
+        JdbcConfig.JDBC_DRIVER.getKey(), 
OCEANBASE_CONTAINER.getDriverClassName(TEST_DB_NAME));
+    catalogProperties.put(JdbcConfig.USERNAME.getKey(), 
OCEANBASE_CONTAINER.getUsername());
+    catalogProperties.put(JdbcConfig.PASSWORD.getKey(), "wrong_password");
+
+    Exception exception =
+        assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    GravitinoITUtils.genRandomName("oceanbase_it_catalog"),
+                    Catalog.Type.RELATIONAL,
+                    provider,
+                    "comment",
+                    catalogProperties));
+    Assertions.assertTrue(exception.getMessage().contains("Access denied for 
user"));
+  }
+
   @Test
   void testCreateAndLoadOceanBaseTable() {
     // Create table from Gravitino API
diff --git 
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/converter/PostgreSqlExceptionConverter.java
 
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/converter/PostgreSqlExceptionConverter.java
index d9931bbd7..4bae02cf7 100644
--- 
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/converter/PostgreSqlExceptionConverter.java
+++ 
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/converter/PostgreSqlExceptionConverter.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.catalog.postgresql.converter;
 
 import java.sql.SQLException;
 import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.GravitinoRuntimeException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NoSuchTableException;
@@ -47,6 +48,9 @@ public class PostgreSqlExceptionConverter extends 
JdbcExceptionConverter {
           return new GravitinoRuntimeException(se.getMessage(), se);
       }
     } else {
+      if (se.getMessage() != null && se.getMessage().contains("password 
authentication failed")) {
+        return new ConnectionFailedException(se.getMessage(), se);
+      }
       return new GravitinoRuntimeException(se.getMessage(), se);
     }
   }
diff --git 
a/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/integration/test/CatalogPostgreSqlIT.java
 
b/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/integration/test/CatalogPostgreSqlIT.java
index f22073c78..558775014 100644
--- 
a/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/integration/test/CatalogPostgreSqlIT.java
+++ 
b/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/integration/test/CatalogPostgreSqlIT.java
@@ -44,6 +44,7 @@ import org.apache.gravitino.auth.AuthConstants;
 import org.apache.gravitino.catalog.jdbc.config.JdbcConfig;
 import 
org.apache.gravitino.catalog.postgresql.integration.test.service.PostgreSqlService;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.SchemaAlreadyExistsException;
 import org.apache.gravitino.integration.test.container.ContainerSuite;
@@ -239,6 +240,32 @@ public class CatalogPostgreSqlIT extends BaseIT {
     };
   }
 
+  @Test
+  void testTestConnection() throws SQLException {
+    Map<String, String> catalogProperties = Maps.newHashMap();
+
+    String jdbcUrl = POSTGRESQL_CONTAINER.getJdbcUrl(TEST_DB_NAME);
+    catalogProperties.put(
+        JdbcConfig.JDBC_DRIVER.getKey(), 
POSTGRESQL_CONTAINER.getDriverClassName(TEST_DB_NAME));
+    catalogProperties.put(JdbcConfig.JDBC_URL.getKey(), jdbcUrl);
+    catalogProperties.put(JdbcConfig.JDBC_DATABASE.getKey(), 
TEST_DB_NAME.toString());
+    catalogProperties.put(JdbcConfig.USERNAME.getKey(), 
POSTGRESQL_CONTAINER.getUsername());
+    catalogProperties.put(JdbcConfig.PASSWORD.getKey(), "wrong_password");
+
+    Exception exception =
+        assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    GravitinoITUtils.genRandomName("postgresql_it_catalog"),
+                    Catalog.Type.RELATIONAL,
+                    provider,
+                    "comment",
+                    catalogProperties));
+    Assertions.assertTrue(
+        exception.getMessage().contains("password authentication failed for 
user"));
+  }
+
   @Test
   void testCreateTableWithArrayType() {
     String tableName = 
GravitinoITUtils.genRandomName("postgresql_it_array_table");
diff --git 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/TestMultipleJDBCLoad.java
 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/TestMultipleJDBCLoad.java
index 4b1edae82..40e437a0f 100644
--- 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/TestMultipleJDBCLoad.java
+++ 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/TestMultipleJDBCLoad.java
@@ -31,6 +31,7 @@ import java.util.Map;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
 import org.apache.gravitino.integration.test.container.MySQLContainer;
 import org.apache.gravitino.integration.test.container.PostgreSQLContainer;
@@ -96,8 +97,24 @@ public class TestMultipleJDBCLoad extends BaseIT {
     icebergMysqlConf.put(
         IcebergConfig.JDBC_DRIVER.getKey(), 
mySQLContainer.getDriverClassName(TEST_DB_NAME));
     icebergMysqlConf.put(GRAVITINO_JDBC_USER, mySQLContainer.getUsername());
-    icebergMysqlConf.put(GRAVITINO_JDBC_PASSWORD, 
mySQLContainer.getPassword());
+    icebergMysqlConf.put(GRAVITINO_JDBC_PASSWORD, "wrong_password");
     String mysqlCatalogName = 
RandomNameUtils.genRandomName("it_iceberg_mysql");
+
+    // test wrong password
+    Exception exception =
+        Assertions.assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    mysqlCatalogName,
+                    Catalog.Type.RELATIONAL,
+                    "lakehouse-iceberg",
+                    "comment",
+                    icebergMysqlConf));
+    Assertions.assertTrue(exception.getMessage().contains("Access denied for 
user"));
+
+    // test correct password
+    icebergMysqlConf.put(GRAVITINO_JDBC_PASSWORD, 
mySQLContainer.getPassword());
     Catalog mysqlCatalog =
         metalake.createCatalog(
             mysqlCatalogName,
diff --git 
a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/utils/CatalogUtils.java
 
b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/utils/CatalogUtils.java
index 46671e12e..3ae48576c 100644
--- 
a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/utils/CatalogUtils.java
+++ 
b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/utils/CatalogUtils.java
@@ -30,6 +30,7 @@ import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY
 
 import com.google.common.base.Preconditions;
 import java.io.File;
+import java.sql.SQLException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -39,6 +40,7 @@ import 
org.apache.gravitino.catalog.lakehouse.paimon.PaimonConfig;
 import 
org.apache.gravitino.catalog.lakehouse.paimon.authentication.AuthenticationConfig;
 import 
org.apache.gravitino.catalog.lakehouse.paimon.authentication.kerberos.KerberosClient;
 import 
org.apache.gravitino.catalog.lakehouse.paimon.ops.PaimonBackendCatalogWrapper;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.paimon.catalog.Catalog;
 import org.apache.paimon.catalog.CatalogContext;
@@ -103,11 +105,20 @@ public class CatalogUtils {
    * @param paimonConfig The Paimon configuration.
    * @return The {@link Catalog} instance of catalog backend.
    */
+  @SuppressWarnings("FormatStringAnnotation")
   public static Catalog loadCatalogBackendWithSimpleAuth(PaimonConfig 
paimonConfig) {
     checkPaimonConfig(paimonConfig);
     CatalogContext catalogContext =
         CatalogContext.create(Options.fromMap(paimonConfig.getAllConfig()));
-    return CatalogFactory.createCatalog(catalogContext);
+    try {
+      return CatalogFactory.createCatalog(catalogContext);
+    } catch (RuntimeException e) {
+      if (e.getCause() instanceof SQLException
+          && e.getCause().getMessage().contains("Access denied")) {
+        throw new ConnectionFailedException(e, e.getMessage());
+      }
+      throw e;
+    }
   }
 
   private static void checkPaimonConfig(PaimonConfig paimonConfig) {
diff --git 
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonBaseIT.java
 
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonBaseIT.java
index a61702507..b2c6d624a 100644
--- 
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonBaseIT.java
+++ 
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonBaseIT.java
@@ -104,7 +104,7 @@ public abstract class CatalogPaimonBaseIT extends BaseIT {
   protected String schemaName = 
GravitinoITUtils.genRandomName("paimon_it_schema");
   protected static final String schema_comment = "schema_comment";
 
-  private static final String provider = "lakehouse-paimon";
+  protected static final String provider = "lakehouse-paimon";
   private static final String catalog_comment = "catalog_comment";
   private static final String table_comment = "table_comment";
   private static final String PAIMON_COL_NAME1 = "paimon_col_name1";
@@ -116,7 +116,7 @@ public abstract class CatalogPaimonBaseIT extends BaseIT {
   private static String INSERT_BATCH_WITHOUT_PARTITION_TEMPLATE = "INSERT INTO 
paimon.%s VALUES %s";
   private static final String SELECT_ALL_TEMPLATE = "SELECT * FROM paimon.%s";
   private static final String DEFAULT_DB = "default";
-  private GravitinoMetalake metalake;
+  protected GravitinoMetalake metalake;
   private Map<String, String> catalogProperties;
 
   @BeforeAll
diff --git 
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonJdbcIT.java
 
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonJdbcIT.java
index 863ed50e3..3eb14f132 100644
--- 
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonJdbcIT.java
+++ 
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/integration/test/CatalogPaimonJdbcIT.java
@@ -20,9 +20,14 @@ package 
org.apache.gravitino.catalog.lakehouse.paimon.integration.test;
 
 import com.google.common.collect.Maps;
 import java.util.Map;
+import org.apache.gravitino.Catalog;
 import 
org.apache.gravitino.catalog.lakehouse.paimon.PaimonCatalogPropertiesMetadata;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.integration.test.container.HiveContainer;
+import org.apache.gravitino.integration.test.util.GravitinoITUtils;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
 
 @Tag("gravitino-docker-test")
@@ -58,4 +63,22 @@ public class CatalogPaimonJdbcIT extends CatalogPaimonBaseIT 
{
 
     return catalogProperties;
   }
+
+  @Test
+  void testTestConnection() {
+    Map<String, String> props = initPaimonCatalogProperties();
+    props.put(PaimonCatalogPropertiesMetadata.GRAVITINO_JDBC_PASSWORD, 
"wrong_password");
+
+    Exception exception =
+        Assertions.assertThrows(
+            ConnectionFailedException.class,
+            () ->
+                metalake.testConnection(
+                    GravitinoITUtils.genRandomName("paimon_it_catalog"),
+                    Catalog.Type.RELATIONAL,
+                    provider,
+                    null,
+                    props));
+    Assertions.assertTrue(exception.getMessage().contains("Access denied for 
user"));
+  }
 }
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/ErrorResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/ErrorResponse.java
index c68b71f13..015743bbf 100644
--- a/common/src/main/java/org/apache/gravitino/dto/responses/ErrorResponse.java
+++ b/common/src/main/java/org/apache/gravitino/dto/responses/ErrorResponse.java
@@ -235,7 +235,7 @@ public class ErrorResponse extends BaseResponse {
   }
 
   /**
-   * Create a new entity in use error instance of {@link ErrorResponse}.
+   * Create a new not in use error instance of {@link ErrorResponse}.
    *
    * @param type The type of the error.
    * @param message The message of the error.
@@ -295,7 +295,7 @@ public class ErrorResponse extends BaseResponse {
   }
 
   /**
-   * Create a new unknown error instance of {@link ErrorResponse}.
+   * Create a new oauth error instance of {@link ErrorResponse}.
    *
    * @param code The code of the error.
    * @param type The type of the error.
diff --git 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
index 4e28eb7c8..a2402082f 100644
--- 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
+++ 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
@@ -25,11 +25,13 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import java.io.File;
 import java.io.IOException;
+import java.sql.SQLException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
+import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.iceberg.common.ClosableHiveCatalog;
 import org.apache.gravitino.iceberg.common.IcebergCatalogBackend;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
@@ -44,6 +46,7 @@ import org.apache.iceberg.catalog.Catalog;
 import org.apache.iceberg.hive.HiveCatalog;
 import org.apache.iceberg.inmemory.InMemoryCatalog;
 import org.apache.iceberg.jdbc.JdbcCatalog;
+import org.apache.iceberg.jdbc.UncheckedSQLException;
 import org.apache.iceberg.rest.RESTCatalog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -112,6 +115,7 @@ public class IcebergCatalogUtil {
     }
   }
 
+  @SuppressWarnings("FormatStringAnnotation")
   private static JdbcCatalog loadJdbcCatalog(IcebergConfig icebergConfig) {
     String driverClassName = icebergConfig.getJdbcDriver();
     String icebergCatalogName = icebergConfig.getCatalogBackendName();
@@ -135,7 +139,15 @@ public class IcebergCatalogUtil {
     HdfsConfiguration hdfsConfiguration = new HdfsConfiguration();
     properties.forEach(hdfsConfiguration::set);
     jdbcCatalog.setConf(hdfsConfiguration);
-    jdbcCatalog.initialize(icebergCatalogName, properties);
+    try {
+      jdbcCatalog.initialize(icebergCatalogName, properties);
+    } catch (UncheckedSQLException e) {
+      if (e.getCause() instanceof SQLException
+          && e.getCause().getMessage().contains("Access denied")) {
+        throw new ConnectionFailedException(e, e.getMessage());
+      }
+      throw e;
+    }
     return jdbcCatalog;
   }
 

Reply via email to