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 6aefe3bfb [#5077] feat(core): Add the check of user before creating 
metadata object (#5096)
6aefe3bfb is described below

commit 6aefe3bfbdd23290589495acb6adb3fb28c0e41b
Author: roryqi <[email protected]>
AuthorDate: Mon Oct 14 15:16:23 2024 +0800

    [#5077] feat(core): Add the check of user before creating metadata object 
(#5096)
    
    ### What changes were proposed in this pull request?
    
    Add the check of user before creating metadata object.
    
    ### Why are the changes needed?
    
    Fix: #5077
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    Added UT.
---
 .../gravitino/exceptions/ForbiddenException.java   |  48 ++++
 .../org/apache/gravitino/client/ErrorHandlers.java |  20 ++
 .../test/authorization/CheckCurrentUserIT.java     | 273 +++++++++++++++++++++
 .../gravitino/dto/responses/ErrorConstants.java    |   3 +
 .../gravitino/dto/responses/ErrorResponse.java     |  16 ++
 .../authorization/AuthorizationUtils.java          |  16 ++
 .../hook/AccessControlHookDispatcher.java          |   3 +
 .../gravitino/hook/CatalogHookDispatcher.java      |   5 +
 .../gravitino/hook/FilesetHookDispatcher.java      |   5 +
 .../gravitino/hook/SchemaHookDispatcher.java       |   5 +
 .../apache/gravitino/hook/TableHookDispatcher.java |   5 +
 .../apache/gravitino/hook/TopicHookDispatcher.java |   5 +
 .../org/apache/gravitino/server/web/Utils.java     |   7 +
 .../server/web/rest/ExceptionHandlers.java         |  18 ++
 14 files changed, 429 insertions(+)

diff --git 
a/api/src/main/java/org/apache/gravitino/exceptions/ForbiddenException.java 
b/api/src/main/java/org/apache/gravitino/exceptions/ForbiddenException.java
new file mode 100644
index 000000000..95ee76ad1
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/exceptions/ForbiddenException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.gravitino.exceptions;
+
+import com.google.errorprone.annotations.FormatMethod;
+import com.google.errorprone.annotations.FormatString;
+
+/** Exception thrown when a user is forbidden to perform an action. */
+public class ForbiddenException extends GravitinoRuntimeException {
+  /**
+   * Constructs a new exception with the specified detail message.
+   *
+   * @param message the detail message.
+   * @param args the arguments to the message.
+   */
+  @FormatMethod
+  public ForbiddenException(@FormatString String message, Object... args) {
+    super(message, args);
+  }
+
+  /**
+   * Constructs a new exception with the specified detail message and cause.
+   *
+   * @param cause the cause.
+   * @param message the detail message.
+   * @param args the arguments to the message.
+   */
+  @FormatMethod
+  public ForbiddenException(Throwable cause, @FormatString String message, 
Object... args) {
+    super(cause, message, args);
+  }
+}
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
index 5ab440092..ca50af1b9 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
@@ -30,6 +30,7 @@ import org.apache.gravitino.exceptions.BadRequestException;
 import org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
 import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.FilesetAlreadyExistsException;
+import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
 import org.apache.gravitino.exceptions.IllegalPrivilegeException;
 import org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
@@ -303,9 +304,13 @@ public class ErrorHandlers {
 
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
+
         case ErrorConstants.UNSUPPORTED_OPERATION_CODE:
           throw new UnsupportedOperationException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         default:
           super.accept(errorResponse);
       }
@@ -343,6 +348,9 @@ public class ErrorHandlers {
         case ErrorConstants.UNSUPPORTED_OPERATION_CODE:
           throw new UnsupportedOperationException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
 
@@ -380,6 +388,9 @@ public class ErrorHandlers {
         case ErrorConstants.ALREADY_EXISTS_CODE:
           throw new CatalogAlreadyExistsException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
 
@@ -495,6 +506,9 @@ public class ErrorHandlers {
         case ErrorConstants.ALREADY_EXISTS_CODE:
           throw new FilesetAlreadyExistsException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
 
@@ -530,6 +544,9 @@ public class ErrorHandlers {
         case ErrorConstants.ALREADY_EXISTS_CODE:
           throw new TopicAlreadyExistsException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
 
@@ -652,6 +669,9 @@ public class ErrorHandlers {
         case ErrorConstants.UNSUPPORTED_OPERATION_CODE:
           throw new UnsupportedOperationException(errorMessage);
 
+        case ErrorConstants.FORBIDDEN_CODE:
+          throw new ForbiddenException(errorMessage);
+
         case ErrorConstants.INTERNAL_ERROR_CODE:
           throw new RuntimeException(errorMessage);
 
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/CheckCurrentUserIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/CheckCurrentUserIT.java
new file mode 100644
index 000000000..2f80a3102
--- /dev/null
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/CheckCurrentUserIT.java
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.gravitino.client.integration.test.authorization;
+
+import static 
org.apache.gravitino.server.GravitinoServer.WEBSERVER_CONF_PREFIX;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.gravitino.Catalog;
+import org.apache.gravitino.Configs;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.auth.AuthConstants;
+import org.apache.gravitino.authorization.Privileges;
+import org.apache.gravitino.authorization.SecurableObject;
+import org.apache.gravitino.authorization.SecurableObjects;
+import org.apache.gravitino.client.GravitinoAdminClient;
+import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ForbiddenException;
+import org.apache.gravitino.file.Fileset;
+import org.apache.gravitino.integration.test.container.ContainerSuite;
+import org.apache.gravitino.integration.test.container.HiveContainer;
+import org.apache.gravitino.integration.test.container.KafkaContainer;
+import org.apache.gravitino.integration.test.util.AbstractIT;
+import org.apache.gravitino.rel.Column;
+import org.apache.gravitino.rel.types.Types;
+import org.apache.gravitino.server.web.JettyServerConfig;
+import org.apache.gravitino.utils.RandomNameUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Tag("gravitino-docker-test")
+public class CheckCurrentUserIT extends AbstractIT {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(CheckCurrentUserIT.class);
+  private static final ContainerSuite containerSuite = 
ContainerSuite.getInstance();
+  private static String hmsUri;
+  private static String kafkaBootstrapServers;
+  private static GravitinoMetalake metalake;
+  private static GravitinoMetalake anotherMetalake;
+  private static String metalakeName = 
RandomNameUtils.genRandomName("metalake");
+
+  @BeforeAll
+  public static void startIntegrationTest() throws Exception {
+    Map<String, String> configs = Maps.newHashMap();
+    configs.put(Configs.ENABLE_AUTHORIZATION.getKey(), String.valueOf(true));
+    configs.put(Configs.SERVICE_ADMINS.getKey(), AuthConstants.ANONYMOUS_USER);
+    registerCustomConfigs(configs);
+    AbstractIT.startIntegrationTest();
+
+    containerSuite.startHiveContainer();
+    hmsUri =
+        String.format(
+            "thrift://%s:%d",
+            containerSuite.getHiveContainer().getContainerIpAddress(),
+            HiveContainer.HIVE_METASTORE_PORT);
+
+    containerSuite.startKafkaContainer();
+    kafkaBootstrapServers =
+        String.format(
+            "%s:%d",
+            containerSuite.getKafkaContainer().getContainerIpAddress(),
+            KafkaContainer.DEFAULT_BROKER_PORT);
+
+    JettyServerConfig jettyServerConfig =
+        JettyServerConfig.fromConfig(serverConfig, WEBSERVER_CONF_PREFIX);
+
+    String uri = "http://"; + jettyServerConfig.getHost() + ":" + 
jettyServerConfig.getHttpPort();
+    System.setProperty("user.name", "test");
+    GravitinoAdminClient anotherClient = 
GravitinoAdminClient.builder(uri).withSimpleAuth().build();
+
+    metalake = client.createMetalake(metalakeName, "metalake comment", 
Collections.emptyMap());
+    anotherMetalake = anotherClient.loadMetalake(metalakeName);
+  }
+
+  @AfterAll
+  public static void tearDown() {
+    if (client != null) {
+      client.dropMetalake(metalakeName);
+      client.close();
+      client = null;
+    }
+
+    try {
+      closer.close();
+    } catch (Exception e) {
+      LOG.error("Exception in closing CloseableGroup", e);
+    }
+  }
+
+  @Test
+  public void testCreateTopic() {
+    String catalogName = RandomNameUtils.genRandomName("catalogA");
+
+    Map<String, String> properties = Maps.newHashMap();
+    properties.put("bootstrap.servers", kafkaBootstrapServers);
+
+    // Test to create catalog with not-existed user
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherMetalake.createCatalog(
+                catalogName, Catalog.Type.MESSAGING, "kafka", "comment", 
properties));
+
+    Catalog catalog =
+        metalake.createCatalog(catalogName, Catalog.Type.MESSAGING, "kafka", 
"comment", properties);
+
+    // Test to create topic with not-existed user
+    metalake.addUser("test");
+    Catalog anotherCatalog = anotherMetalake.loadCatalog(catalogName);
+    metalake.removeUser("test");
+    NameIdentifier topicIdent = NameIdentifier.of("default", "topic");
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherCatalog
+                .asTopicCatalog()
+                .createTopic(topicIdent, "comment", null, 
Collections.emptyMap()));
+
+    Assertions.assertDoesNotThrow(
+        () ->
+            catalog
+                .asTopicCatalog()
+                .createTopic(topicIdent, "comment", null, 
Collections.emptyMap()));
+    catalog.asTopicCatalog().dropTopic(topicIdent);
+
+    metalake.dropCatalog(catalogName);
+  }
+
+  @Test
+  public void testCreateFileset() {
+    String catalogName = RandomNameUtils.genRandomName("catalog");
+    // Test to create a fileset with a not-existed user
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherMetalake.createCatalog(
+                catalogName, Catalog.Type.FILESET, "hadoop", "comment", 
Collections.emptyMap()));
+
+    Catalog catalog =
+        metalake.createCatalog(
+            catalogName, Catalog.Type.FILESET, "hadoop", "comment", 
Collections.emptyMap());
+
+    // Test to create a schema with a not-existed user
+    Catalog anotherCatalog = anotherMetalake.loadCatalog(catalogName);
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () -> anotherCatalog.asSchemas().createSchema("schema", "comment", 
Collections.emptyMap()));
+
+    catalog.asSchemas().createSchema("schema", "comment", 
Collections.emptyMap());
+
+    // Test to create a fileset with a not-existed user
+    NameIdentifier fileIdent = NameIdentifier.of("schema", "fileset");
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherCatalog
+                .asFilesetCatalog()
+                .createFileset(
+                    fileIdent, "comment", Fileset.Type.EXTERNAL, "tmp", 
Collections.emptyMap()));
+
+    Assertions.assertDoesNotThrow(
+        () ->
+            catalog
+                .asFilesetCatalog()
+                .createFileset(
+                    fileIdent, "comment", Fileset.Type.EXTERNAL, "tmp", 
Collections.emptyMap()));
+
+    // Clean up
+    catalog.asFilesetCatalog().dropFileset(fileIdent);
+    catalog.asSchemas().dropSchema("schema", true);
+    metalake.dropCatalog(catalogName);
+  }
+
+  @Test
+  public void testCreateRole() {
+    SecurableObject metalakeSecObject =
+        SecurableObjects.ofMetalake(
+            metalakeName, 
Lists.newArrayList(Privileges.CreateCatalog.allow()));
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherMetalake.createRole(
+                "role", Collections.emptyMap(), 
Lists.newArrayList(metalakeSecObject)));
+
+    Assertions.assertDoesNotThrow(
+        () ->
+            metalake.createRole(
+                "role", Collections.emptyMap(), 
Lists.newArrayList(metalakeSecObject)));
+    metalake.deleteRole("role");
+  }
+
+  @Test
+  public void testCreateTable() {
+    String catalogName = RandomNameUtils.genRandomName("catalog");
+    Map<String, String> properties = Maps.newHashMap();
+    properties.put("metastore.uris", hmsUri);
+
+    // Test to create catalog with not-existed user
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherMetalake.createCatalog(
+                catalogName, Catalog.Type.RELATIONAL, "hive", "catalog 
comment", properties));
+    Catalog catalog =
+        metalake.createCatalog(
+            catalogName, Catalog.Type.RELATIONAL, "hive", "catalog comment", 
properties);
+
+    // Test to create schema with not-existed user
+    Catalog anotherCatalog = anotherMetalake.loadCatalog(catalogName);
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () -> anotherCatalog.asSchemas().createSchema("schema", "comment", 
Collections.emptyMap()));
+
+    catalog.asSchemas().createSchema("schema", "comment", 
Collections.emptyMap());
+
+    // Test to create table with not-existed user
+    NameIdentifier tableIdent = NameIdentifier.of("schema", "table");
+    Assertions.assertThrows(
+        ForbiddenException.class,
+        () ->
+            anotherCatalog
+                .asTableCatalog()
+                .createTable(
+                    tableIdent,
+                    new Column[] {
+                      Column.of("col1", Types.IntegerType.get()),
+                      Column.of("col2", Types.StringType.get())
+                    },
+                    "comment",
+                    Collections.emptyMap()));
+
+    Assertions.assertDoesNotThrow(
+        () ->
+            catalog
+                .asTableCatalog()
+                .createTable(
+                    tableIdent,
+                    new Column[] {
+                      Column.of("col1", Types.IntegerType.get()),
+                      Column.of("col2", Types.StringType.get())
+                    },
+                    "comment",
+                    Collections.emptyMap()));
+
+    // Clean up
+    catalog.asTableCatalog().dropTable(tableIdent);
+    catalog.asSchemas().dropSchema("schema", true);
+    metalake.dropCatalog(catalogName);
+  }
+}
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/ErrorConstants.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/ErrorConstants.java
index 8772a09d1..db799ac18 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/ErrorConstants.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/ErrorConstants.java
@@ -45,6 +45,9 @@ public class ErrorConstants {
   /** Error codes for connect to catalog failed. */
   public static final int CONNECTION_FAILED_CODE = 1007;
 
+  /** Error codes for forbidden operation. */
+  public static final int FORBIDDEN_CODE = 1008;
+
   /** Error codes for invalid state. */
   public static final int UNKNOWN_ERROR_CODE = 1100;
 
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 86e619bc7..2c1e1e9ef 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
@@ -28,6 +28,7 @@ import javax.annotation.Nullable;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import org.apache.gravitino.exceptions.ConnectionFailedException;
+import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.RESTException;
 
 /** Represents an error response. */
@@ -305,6 +306,21 @@ public class ErrorResponse extends BaseResponse {
         getStackTrace(throwable));
   }
 
+  /**
+   * Create a new forbidden operation error instance of {@link ErrorResponse}.
+   *
+   * @param message The message of the error.
+   * @param throwable The throwable that caused the error.
+   * @return The new instance.
+   */
+  public static ErrorResponse forbidden(String message, Throwable throwable) {
+    return new ErrorResponse(
+        ErrorConstants.FORBIDDEN_CODE,
+        ForbiddenException.class.getSimpleName(),
+        message,
+        getStackTrace(throwable));
+  }
+
   private static List<String> getStackTrace(Throwable throwable) {
     if (throwable == null) {
       return null;
diff --git 
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java 
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
index 51f5cae62..81447abfd 100644
--- 
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
+++ 
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
@@ -36,10 +36,12 @@ import org.apache.gravitino.connector.BaseCatalog;
 import org.apache.gravitino.connector.authorization.AuthorizationPlugin;
 import org.apache.gravitino.dto.authorization.PrivilegeDTO;
 import org.apache.gravitino.dto.util.DTOConverters;
+import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.IllegalPrivilegeException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchUserException;
 import org.apache.gravitino.utils.MetadataObjectUtil;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.slf4j.Logger;
@@ -81,6 +83,20 @@ public class AuthorizationUtils {
     }
   }
 
+  public static void checkCurrentUser(String metalake, String user) {
+    try {
+      AccessControlDispatcher dispatcher = 
GravitinoEnv.getInstance().accessControlDispatcher();
+      // Only when we enable authorization, we need to check the current user
+      if (dispatcher != null) {
+        dispatcher.getUser(metalake, user);
+      }
+    } catch (NoSuchUserException nsu) {
+      throw new ForbiddenException(
+          "Current user %s doesn't exist in the metalake %s, you should add 
the user to the metalake first",
+          user, metalake);
+    }
+  }
+
   public static NameIdentifier ofRole(String metalake, String role) {
     return NameIdentifier.of(
         metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.ROLE_SCHEMA_NAME, role);
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/AccessControlHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/AccessControlHookDispatcher.java
index 36f75cfad..125df0b2e 100644
--- 
a/core/src/main/java/org/apache/gravitino/hook/AccessControlHookDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/hook/AccessControlHookDispatcher.java
@@ -145,6 +145,9 @@ public class AccessControlHookDispatcher implements 
AccessControlDispatcher {
       Map<String, String> properties,
       List<SecurableObject> securableObjects)
       throws RoleAlreadyExistsException, NoSuchMetalakeException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(metalake, 
PrincipalUtils.getCurrentUserName());
+
     Role createdRole = dispatcher.createRole(metalake, role, properties, 
securableObjects);
 
     // Set the creator as the owner of role.
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/CatalogHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/CatalogHookDispatcher.java
index 86b42dea3..7a9989f4e 100644
--- a/core/src/main/java/org/apache/gravitino/hook/CatalogHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/CatalogHookDispatcher.java
@@ -25,6 +25,7 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.FutureGrantManager;
 import org.apache.gravitino.authorization.Owner;
 import org.apache.gravitino.authorization.OwnerManager;
@@ -71,6 +72,10 @@ public class CatalogHookDispatcher implements 
CatalogDispatcher {
       String comment,
       Map<String, String> properties)
       throws NoSuchMetalakeException, CatalogAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
     Catalog catalog = dispatcher.createCatalog(ident, type, provider, comment, 
properties);
 
     // Set the creator as the owner of the catalog.
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/FilesetHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/FilesetHookDispatcher.java
index e77801355..e3272846d 100644
--- a/core/src/main/java/org/apache/gravitino/hook/FilesetHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/FilesetHookDispatcher.java
@@ -23,6 +23,7 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.Owner;
 import org.apache.gravitino.authorization.OwnerManager;
 import org.apache.gravitino.catalog.FilesetDispatcher;
@@ -64,6 +65,10 @@ public class FilesetHookDispatcher implements 
FilesetDispatcher {
       String storageLocation,
       Map<String, String> properties)
       throws NoSuchSchemaException, FilesetAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
     Fileset fileset = dispatcher.createFileset(ident, comment, type, 
storageLocation, properties);
 
     // Set the creator as the owner of the fileset.
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/SchemaHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/SchemaHookDispatcher.java
index d9bcf0417..8b53f6e6d 100644
--- a/core/src/main/java/org/apache/gravitino/hook/SchemaHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/SchemaHookDispatcher.java
@@ -25,6 +25,7 @@ import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.Schema;
 import org.apache.gravitino.SchemaChange;
+import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.Owner;
 import org.apache.gravitino.authorization.OwnerManager;
 import org.apache.gravitino.catalog.SchemaDispatcher;
@@ -55,6 +56,10 @@ public class SchemaHookDispatcher implements 
SchemaDispatcher {
   @Override
   public Schema createSchema(NameIdentifier ident, String comment, Map<String, 
String> properties)
       throws NoSuchCatalogException, SchemaAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
     Schema schema = dispatcher.createSchema(ident, comment, properties);
 
     // Set the creator as the owner of the schema.
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/TableHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/TableHookDispatcher.java
index 3a39f0a9d..c887746b4 100644
--- a/core/src/main/java/org/apache/gravitino/hook/TableHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/TableHookDispatcher.java
@@ -23,6 +23,7 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.Owner;
 import org.apache.gravitino.authorization.OwnerManager;
 import org.apache.gravitino.catalog.TableDispatcher;
@@ -72,6 +73,10 @@ public class TableHookDispatcher implements TableDispatcher {
       SortOrder[] sortOrders,
       Index[] indexes)
       throws NoSuchSchemaException, TableAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
     Table table =
         dispatcher.createTable(
             ident, columns, comment, properties, partitions, distribution, 
sortOrders, indexes);
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/TopicHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/TopicHookDispatcher.java
index c36e58e6f..ad0ec8c58 100644
--- a/core/src/main/java/org/apache/gravitino/hook/TopicHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/TopicHookDispatcher.java
@@ -23,6 +23,7 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.Owner;
 import org.apache.gravitino.authorization.OwnerManager;
 import org.apache.gravitino.catalog.TopicDispatcher;
@@ -61,6 +62,10 @@ public class TopicHookDispatcher implements TopicDispatcher {
   public Topic createTopic(
       NameIdentifier ident, String comment, DataLayout dataLayout, Map<String, 
String> properties)
       throws NoSuchSchemaException, TopicAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
     Topic topic = dispatcher.createTopic(ident, comment, dataLayout, 
properties);
 
     // Set the creator as the owner of the topic.
diff --git a/server/src/main/java/org/apache/gravitino/server/web/Utils.java 
b/server/src/main/java/org/apache/gravitino/server/web/Utils.java
index 7226eb363..86d2f8d1b 100644
--- a/server/src/main/java/org/apache/gravitino/server/web/Utils.java
+++ b/server/src/main/java/org/apache/gravitino/server/web/Utils.java
@@ -148,6 +148,13 @@ public class Utils {
         .build();
   }
 
+  public static Response forbidden(String message, Throwable throwable) {
+    return Response.status(Response.Status.FORBIDDEN)
+        .entity(ErrorResponse.forbidden(message, throwable))
+        .type(MediaType.APPLICATION_JSON)
+        .build();
+  }
+
   public static Response doAs(
       HttpServletRequest httpRequest, PrivilegedExceptionAction<Response> 
action) throws Exception {
     UserPrincipal principal =
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
index 4748cf23d..dd8c21ab4 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
@@ -26,6 +26,7 @@ import org.apache.gravitino.exceptions.AlreadyExistsException;
 import org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
 import org.apache.gravitino.exceptions.ConnectionFailedException;
 import org.apache.gravitino.exceptions.FilesetAlreadyExistsException;
+import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
 import org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
@@ -212,6 +213,9 @@ public class ExceptionHandlers {
       } else if (e instanceof UnsupportedOperationException) {
         return Utils.unsupportedOperation(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
+
       } else {
         return super.handle(op, table, schema, e);
       }
@@ -250,6 +254,9 @@ public class ExceptionHandlers {
       } else if (e instanceof UnsupportedOperationException) {
         return Utils.unsupportedOperation(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
+
       } else {
         return super.handle(op, schema, catalog, e);
       }
@@ -282,6 +289,9 @@ public class ExceptionHandlers {
       } else if (e instanceof NotFoundException) {
         return Utils.notFound(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
+
       } else if (e instanceof CatalogAlreadyExistsException) {
         return Utils.alreadyExists(errorMsg, e);
 
@@ -347,6 +357,9 @@ public class ExceptionHandlers {
       } else if (e instanceof FilesetAlreadyExistsException) {
         return Utils.alreadyExists(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
+
       } else {
         return super.handle(op, fileset, schema, e);
       }
@@ -449,6 +462,9 @@ public class ExceptionHandlers {
       } else if (e instanceof RoleAlreadyExistsException) {
         return Utils.alreadyExists(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
+
       } else {
         return super.handle(op, role, metalake, e);
       }
@@ -480,6 +496,8 @@ public class ExceptionHandlers {
       } else if (e instanceof TopicAlreadyExistsException) {
         return Utils.alreadyExists(errorMsg, e);
 
+      } else if (e instanceof ForbiddenException) {
+        return Utils.forbidden(errorMsg, e);
       } else {
         return super.handle(op, topic, schema, e);
       }

Reply via email to