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);
}