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 f40b67672c [#8849] feat(authz): Add metadata authentication for
statistics operations (#8878)
f40b67672c is described below
commit f40b67672cb973b08575858d8928b808cc31611d
Author: roryqi <[email protected]>
AuthorDate: Fri Oct 24 10:58:10 2025 +0800
[#8849] feat(authz): Add metadata authentication for statistics operations
(#8878)
### What changes were proposed in this pull request?
Add metadata authentication for statistics operations
### Why are the changes needed?
Fix: #8849
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Added IT.
---
.../authorization/StatisticAuthorizationIT.java | 192 +++++++++++++++++++++
docs/security/access-control.md | 128 +++++++-------
.../server/authorization/MetadataFilterHelper.java | 2 +-
.../annotations/AuthorizationFullName.java | 28 +++
.../annotations/AuthorizationObjectType.java | 28 +++
.../web/filter/GravitinoInterceptionService.java | 42 ++++-
.../server/web/rest/StatisticOperations.java | 83 +++++++--
7 files changed, 422 insertions(+), 81 deletions(-)
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/StatisticAuthorizationIT.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/StatisticAuthorizationIT.java
new file mode 100644
index 0000000000..6dd0433149
--- /dev/null
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/StatisticAuthorizationIT.java
@@ -0,0 +1,192 @@
+/*
+ * 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.junit.Assert.assertThrows;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.gravitino.Catalog;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.authorization.Owner;
+import org.apache.gravitino.authorization.Privileges;
+import org.apache.gravitino.authorization.SecurableObject;
+import org.apache.gravitino.authorization.SecurableObjects;
+import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.exceptions.ForbiddenException;
+import org.apache.gravitino.integration.test.container.ContainerSuite;
+import org.apache.gravitino.integration.test.container.HiveContainer;
+import org.apache.gravitino.rel.Column;
+import org.apache.gravitino.rel.Table;
+import org.apache.gravitino.rel.TableCatalog;
+import org.apache.gravitino.rel.types.Types;
+import org.apache.gravitino.stats.PartitionRange;
+import org.apache.gravitino.stats.PartitionStatisticsDrop;
+import org.apache.gravitino.stats.PartitionStatisticsModification;
+import org.apache.gravitino.stats.PartitionStatisticsUpdate;
+import org.apache.gravitino.stats.StatisticValue;
+import org.apache.gravitino.stats.StatisticValues;
+import org.apache.gravitino.stats.SupportsPartitionStatistics;
+import org.apache.gravitino.stats.SupportsStatistics;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+@Tag("gravitino-docker-test")
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class StatisticAuthorizationIT extends BaseRestApiAuthorizationIT {
+ private static final String CATALOG = "catalog_stats";
+ private static final String SCHEMA = "schema_stats";
+ private static final ContainerSuite containerSuite =
ContainerSuite.getInstance();
+ private static String hmsUri;
+ private static String role = "role_stats";
+
+ @BeforeAll
+ public void startIntegrationTest() throws Exception {
+ containerSuite.startHiveContainer();
+ super.startIntegrationTest();
+ hmsUri =
+ String.format(
+ "thrift://%s:%d",
+ containerSuite.getHiveContainer().getContainerIpAddress(),
+ HiveContainer.HIVE_METASTORE_PORT);
+ Map<String, String> properties = Maps.newHashMap();
+ properties.put("metastore.uris", hmsUri);
+ GravitinoMetalake metalake = client.loadMetalake(METALAKE);
+
+ metalake
+ .createCatalog(CATALOG, Catalog.Type.RELATIONAL, "hive", "comment",
properties)
+ .asSchemas()
+ .createSchema(SCHEMA, "test", new HashMap<>());
+
+ TableCatalog tableCatalog =
client.loadMetalake(METALAKE).loadCatalog(CATALOG).asTableCatalog();
+ tableCatalog.createTable(
+ NameIdentifier.of(SCHEMA, "table1"), createColumns(), "test", new
HashMap<>());
+
+ List<SecurableObject> securableObjects = new ArrayList<>();
+ SecurableObject catalogObject =
+ SecurableObjects.ofCatalog(
+ CATALOG, ImmutableList.of(Privileges.UseCatalog.allow(),
Privileges.UseSchema.allow()));
+ securableObjects.add(catalogObject);
+ metalake.createRole(role, new HashMap<>(), securableObjects);
+ metalake.grantRolesToUser(ImmutableList.of(role), NORMAL_USER);
+ }
+
+ private Column[] createColumns() {
+ return new Column[] {Column.of("col1", Types.StringType.get())};
+ }
+
+ @Test
+ @Order(1)
+ public void testListStatistics() {
+ TableCatalog tableCatalogNormalUser =
+
normalUserClient.loadMetalake(METALAKE).loadCatalog(CATALOG).asTableCatalog();
+ // normal user can't load table1
+ assertThrows(
+ String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA,
"table1"),
+ ForbiddenException.class,
+ () -> {
+ tableCatalogNormalUser.loadTable(NameIdentifier.of(SCHEMA,
"table1"));
+ });
+
+ // grant normal user privilege to use table1
+ GravitinoMetalake gravitinoMetalake = client.loadMetalake(METALAKE);
+ gravitinoMetalake.grantPrivilegesToRole(
+ role,
+ MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA),
MetadataObject.Type.SCHEMA),
+ ImmutableList.of(Privileges.SelectTable.allow()));
+ Table table = tableCatalogNormalUser.loadTable(NameIdentifier.of(SCHEMA,
"table1"));
+
+ // Can list statistics and partition statistics
+ table.supportsStatistics().listStatistics();
+ table
+ .supportsPartitionStatistics()
+ .listPartitionStatistics(PartitionRange.upTo("p0",
PartitionRange.BoundType.CLOSED));
+ }
+
+ @Test
+ @Order(2)
+ public void testModifyStatistics() {
+ GravitinoMetalake gravitinoMetalake = client.loadMetalake(METALAKE);
+ TableCatalog tableCatalogNormalUser =
+
normalUserClient.loadMetalake(METALAKE).loadCatalog(CATALOG).asTableCatalog();
+
+ // normal user cannot modify table1 statistics (no privilege)
+ Map<String, StatisticValue<?>> statistics = Maps.newHashMap();
+ statistics.put("custom-k1", StatisticValues.longValue(100L));
+ Table table = tableCatalogNormalUser.loadTable(NameIdentifier.of(SCHEMA,
"table1"));
+ SupportsStatistics supportsStatistics = table.supportsStatistics();
+ SupportsPartitionStatistics supportsPartitionStatistics =
table.supportsPartitionStatistics();
+
+ assertThrows(
+ String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA,
"table1"),
+ ForbiddenException.class,
+ () -> {
+ supportsStatistics.updateStatistics(statistics);
+ });
+
+ List<PartitionStatisticsUpdate> updates =
+ Lists.newArrayList(PartitionStatisticsModification.update("p1",
statistics));
+ assertThrows(
+ String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA,
"table1"),
+ ForbiddenException.class,
+ () -> {
+ supportsPartitionStatistics.updatePartitionStatistics(updates);
+ });
+
+ assertThrows(
+ String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA,
"table1"),
+ ForbiddenException.class,
+ () -> {
+ supportsStatistics.dropStatistics(Lists.newArrayList("custom-k1"));
+ });
+
+ List<PartitionStatisticsDrop> drops =
+ Lists.newArrayList(
+ PartitionStatisticsModification.drop("p1",
Lists.newArrayList("custom-k1")));
+ assertThrows(
+ String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA,
"table1"),
+ ForbiddenException.class,
+ () -> {
+ supportsPartitionStatistics.dropPartitionStatistics(drops);
+ });
+
+ // grant normal user owner privilege on table1
+ gravitinoMetalake.setOwner(
+ MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA, "table1"),
MetadataObject.Type.TABLE),
+ NORMAL_USER,
+ Owner.Type.USER);
+
+ // Can update and drop statistics and partition statistics
+
+ supportsStatistics.updateStatistics(statistics);
+ supportsPartitionStatistics.updatePartitionStatistics(updates);
+
+ supportsStatistics.dropStatistics(Lists.newArrayList("custom-k1"));
+ supportsPartitionStatistics.dropPartitionStatistics(drops);
+ }
+}
diff --git a/docs/security/access-control.md b/docs/security/access-control.md
index dfb33c8be5..cb1d7a960e 100644
--- a/docs/security/access-control.md
+++ b/docs/security/access-control.md
@@ -958,65 +958,71 @@ You can follow the steps to achieve the authorization of
Gravitino.
The following table lists the required privileges for each API.
-| API | Required Conditions(s)
|
-|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| create metalake | The user must be the service admins,
configured in the server configurations.
|
-| load metalake | The user is in the metalake
|
-| alter metalake | The owner of the metalake
|
-| drop metalake | The owner of the metalake
|
-| create catalog | `CREATE_CATALOG` on the metalake or the owner
of the metalake
|
-| alter catalog | The owner of the catalog, metalake
|
-| drop catalog | The owner of the catalog, metalake
|
-| list catalog | The owner of the metalake can see all the
catalogs, others can see the catalogs which they can load
|
-| load catalog | The one of owners of the metalake, catalog or
have `USE_CATALOG` on the metalake,catalog
|
-| create schema | `CREATE_SCHEMA` and `USE_CATALOG` on the
metalake, catalog or the owner of the metalake, catalog.
|
-| alter schema | First, you should have the privilege to load
the catalog. Then, you are one of the owners of the schema, catalog, metalake
|
-| drop schema | First, you should have the privilege to load
the catalog. Then, you are one of the owners of the schema, catalog, metalake
|
-| list schema | First, you should have the privilege to load
the catalog. Then, the owner of the metalake, catalog can see all the schemas,
others can see the schemas which they can load.
|
-| load schema | First, you should have the privilege to load
the catalog. Then, you are the owner of the metalake, catalog, schema or have
`USE_SCHEMA` on the metalake, catalog, schema.
|
-| create table | First, you should have the privilege to load
the catalog and the schema. `CREATE_TABLE` on the metalake, catalog, schema or
the owner of the metalake, catalog, schema
|
-| alter table | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
-| drop table | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the table,
schema, catalog, metalake
|
-| list table | First, you should have the privilege to load
the catalog and the schema. Then, the owner of the schema, catalog, metalake
can see all the tables, others can see the tables which they can load
|
-| load table | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the table,
schema, metalake, catalog or have either `SELECT_TABLE` or `MODIFY_TABLE` on
the table, schema, catalog, metalake |
-| create topic | First, you should have the privilege to load
the catalog and the schema. Then, you have `CREATE_TOPIC` on the metalake,
catalog, schema or are the owner of the metalake, catalog, schema
|
-| alter topic | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the topic,
schema,catalog, metalake or have `PRODUCE_TOPIC` on the topic, schema, catalog,
metalake |
-| drop topic | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the topic,
schema, catalog, metalake
|
-| list topic | First, you should have the privilege to load
the catalog and the schema. Then, the owner of the schema, catalog, metalake
can see all the topics, others can see the topics which they can load
|
-| load topic | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the topic,
schema, metalake, catalog or have either `CONSUME_TOPIC` or `PRODUCE_TOPIC` on
the topic, schema, catalog, metalake |
-| create fileset | First, you should have the privilege to load
the catalog and the schema. Then, you have`CREATE_FILESET` on the metalake,
catalog, schema or are the owner of the metalake, catalog, schema
|
-| alter fileset | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the fileset,
schema,catalog, metalake or `WRITE_FILESET` on the fileset, schema, catalog,
metalake |
-| drop fileset | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the fileset,
schema, catalog, metalake
|
-| list fileset | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the schema,
catalog, metalake can see all the filesets, others can see the filesets which
they can load |
-| load fileset | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the fileset,
schema, metalake, catalog or have either `READ_FILESET` or `WRITE_FILESET` on
the fileset, schema, catalog, metalake |
-| list file | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the fileset,
schema, metalake, catalog or have either `READ_FILESET` or `WRITE_FILESET` on
the fileset, schema, catalog, metalake |
-| register model | First, you should have the privilege to load
the catalog and the schema. Then, you have `CREATE_MODEL` on the metalake,
catalog, schema or are the owner of the metalake, catalog, schema
|
-| link model version | First, you should have the privilege to load
the catalog, the schema and the model. Then, you have `CREATE_MODEL_VERSION` on
the metalake, catalog, schema, model or are the owner of the metalake, catalog,
schema, model |
-| alter model | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake
|
-| drop model | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake
|
-| list model | First, you should have the privilege to load
the catalog and the schema. Then the owner of the schema, catalog, metalake can
see all the models, others can see the models which they can load
|
-| load model | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
-| list model version | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake or have `USE_MODEL on the model, schema, catalog,
metalake |
-| load model version | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
-| load model version by alias | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
-| delete model version | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
-| alter model version | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
-| delete model version alias | First, you should have the privilege to load
the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
-| add user | `MANAGE_USERS` on the metalake or the owner
of the metalake
|
-| delete user | `MANAGE_USERS` on the metalake or the owner
of the metalake
|
-| get user | `MANAGE_USERS` on the metalake or the owner
of the metalake or himself
|
-| list users | `MANAGE_USERS` on the metalake or the owner
of the metalake can see all the users, others can see himself
|
-| add group | `MANAGE_GROUPS` on the metalake or the owner
of the metalake
|
-| delete group | `MANAGE_GROUPS` on the metalake or the owner
of the metalake
|
-| get group | `MANAGE_GROUPS` on the metalake or the owner
of the metalake or his groups
|
-| list groups | `MANAGE_GROUPS` on the metalake or the owner
of the metalake can see all the groups, others can see his group
|
-| create role | `CREATE_ROLE` on the metalake or the owner of
the metalake
|
-| delete role | The owner of the metalake or the role
|
-| get role | The owner of the metalake or the role. others
can see his granted or owned roles.
|
-| list roles | The owner of the metalake can see all the
roles. Others can see his granted roles or owned roles.
|
-| grant role | `MANAGE_GRANTS` on the metalake
|
-| revoke role | `MANAGE_GRANTS` on the metalake
|
-| grant privilege | `MANAGE_GRANTS` on the metalake or the owner
of the securable object
|
-| revoke privilege | `MANAGE_GRANTS` on the metalake or the owner
of the securable object
|
-| set owner | The owner of the securable object
|
+| API | Required Conditions(s)
|
+|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| create metalake | The user must be the service admins,
configured in the server configurations.
|
+| load metalake | The user is in the metalake
|
+| alter metalake | The owner of the metalake
|
+| drop metalake | The owner of the metalake
|
+| create catalog | `CREATE_CATALOG` on the metalake or the
owner of the metalake
|
+| alter catalog | The owner of the catalog, metalake
|
+| drop catalog | The owner of the catalog, metalake
|
+| list catalog | The owner of the metalake can see all
the catalogs, others can see the catalogs which they can load
|
+| load catalog | The one of owners of the metalake,
catalog or have `USE_CATALOG` on the metalake,catalog
|
+| create schema | `CREATE_SCHEMA` and `USE_CATALOG` on the
metalake, catalog or the owner of the metalake, catalog.
|
+| alter schema | First, you should have the privilege to
load the catalog. Then, you are one of the owners of the schema, catalog,
metalake
|
+| drop schema | First, you should have the privilege to
load the catalog. Then, you are one of the owners of the schema, catalog,
metalake
|
+| list schema | First, you should have the privilege to
load the catalog. Then, the owner of the metalake, catalog can see all the
schemas, others can see the schemas which they can load.
|
+| load schema | First, you should have the privilege to
load the catalog. Then, you are the owner of the metalake, catalog, schema or
have `USE_SCHEMA` on the metalake, catalog, schema.
|
+| create table | First, you should have the privilege to
load the catalog and the schema. `CREATE_TABLE` on the metalake, catalog,
schema or the owner of the metalake, catalog, schema
|
+| alter table | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
+| update table statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
+| drop table statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
+| update table partition statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
+| drop table partition statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema,catalog, metalake or have `MODIFY_TABLE` on the table, schema, catalog,
metalake |
+| drop table | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema, catalog, metalake
|
+| list table | First, you should have the privilege to
load the catalog and the schema. Then, the owner of the schema, catalog,
metalake can see all the tables, others can see the tables which they can load
|
+| load table | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema, metalake, catalog or have either `SELECT_TABLE` or `MODIFY_TABLE` on
the table, schema, catalog, metalake |
+| list table statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema, metalake, catalog or have either `SELECT_TABLE` or `MODIFY_TABLE` on
the table, schema, catalog, metalake |
+| list table partition statistics | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the table,
schema, metalake, catalog or have either `SELECT_TABLE` or `MODIFY_TABLE` on
the table, schema, catalog, metalake |
+| create topic | First, you should have the privilege to
load the catalog and the schema. Then, you have `CREATE_TOPIC` on the metalake,
catalog, schema or are the owner of the metalake, catalog, schema
|
+| alter topic | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the topic,
schema,catalog, metalake or have `PRODUCE_TOPIC` on the topic, schema, catalog,
metalake |
+| drop topic | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the topic,
schema, catalog, metalake
|
+| list topic | First, you should have the privilege to
load the catalog and the schema. Then, the owner of the schema, catalog,
metalake can see all the topics, others can see the topics which they can load
|
+| load topic | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the topic,
schema, metalake, catalog or have either `CONSUME_TOPIC` or `PRODUCE_TOPIC` on
the topic, schema, catalog, metalake |
+| create fileset | First, you should have the privilege to
load the catalog and the schema. Then, you have`CREATE_FILESET` on the
metalake, catalog, schema or are the owner of the metalake, catalog, schema
|
+| alter fileset | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the
fileset, schema,catalog, metalake or `WRITE_FILESET` on the fileset, schema,
catalog, metalake |
+| drop fileset | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the
fileset, schema, catalog, metalake
|
+| list fileset | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the schema,
catalog, metalake can see all the filesets, others can see the filesets which
they can load |
+| load fileset | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the
fileset, schema, metalake, catalog or have either `READ_FILESET` or
`WRITE_FILESET` on the fileset, schema, catalog, metalake |
+| list file | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the
fileset, schema, metalake, catalog or have either `READ_FILESET` or
`WRITE_FILESET` on the fileset, schema, catalog, metalake |
+| register model | First, you should have the privilege to
load the catalog and the schema. Then, you have `CREATE_MODEL` on the metalake,
catalog, schema or are the owner of the metalake, catalog, schema
|
+| link model version | First, you should have the privilege to
load the catalog, the schema and the model. Then, you have
`CREATE_MODEL_VERSION` on the metalake, catalog, schema, model or are the owner
of the metalake, catalog, schema, model |
+| alter model | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake
|
+| drop model | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake
|
+| list model | First, you should have the privilege to
load the catalog and the schema. Then the owner of the schema, catalog,
metalake can see all the models, others can see the models which they can load
|
+| load model | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
+| list model version | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, catalog, metalake or have `USE_MODEL on the model, schema, catalog,
metalake |
+| load model version | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
+| load model version by alias | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog or have `USE_MODEL on the model, schema, catalog,
metalake |
+| delete model version | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
+| alter model version | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
+| delete model version alias | First, you should have the privilege to
load the catalog and the schema. Then, you are one of the owners of the model,
schema, metalake, catalog.
|
+| add user | `MANAGE_USERS` on the metalake or the
owner of the metalake
|
+| delete user | `MANAGE_USERS` on the metalake or the
owner of the metalake
|
+| get user | `MANAGE_USERS` on the metalake or the
owner of the metalake or himself
|
+| list users | `MANAGE_USERS` on the metalake or the
owner of the metalake can see all the users, others can see himself
|
+| add group | `MANAGE_GROUPS` on the metalake or the
owner of the metalake
|
+| delete group | `MANAGE_GROUPS` on the metalake or the
owner of the metalake
|
+| get group | `MANAGE_GROUPS` on the metalake or the
owner of the metalake or his groups
|
+| list groups | `MANAGE_GROUPS` on the metalake or the
owner of the metalake can see all the groups, others can see his group
|
+| create role | `CREATE_ROLE` on the metalake or the
owner of the metalake
|
+| delete role | The owner of the metalake or the role
|
+| get role | The owner of the metalake or the role.
others can see his granted or owned roles.
|
+| list roles | The owner of the metalake can see all
the roles. Others can see his granted roles or owned roles.
|
+| grant role | `MANAGE_GRANTS` on the metalake
|
+| revoke role | `MANAGE_GRANTS` on the metalake
|
+| grant privilege | `MANAGE_GRANTS` on the metalake or the
owner of the securable object
|
+| revoke privilege | `MANAGE_GRANTS` on the metalake or the
owner of the securable object
|
+| set owner | The owner of the securable object
|
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataFilterHelper.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataFilterHelper.java
index 874424feb2..da16a6967e 100644
---
a/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataFilterHelper.java
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataFilterHelper.java
@@ -232,7 +232,7 @@ public class MetadataFilterHelper {
* @param nameIdentifier metadata name
* @return A map containing the metadata object and all its parent objects,
keyed by their types
*/
- private static Map<Entity.EntityType, NameIdentifier> spiltMetadataNames(
+ public static Map<Entity.EntityType, NameIdentifier> spiltMetadataNames(
String metalake, Entity.EntityType entityType, NameIdentifier
nameIdentifier) {
Map<Entity.EntityType, NameIdentifier> nameIdentifierMap = new HashMap<>();
nameIdentifierMap.put(Entity.EntityType.METALAKE,
NameIdentifierUtil.ofMetalake(metalake));
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationFullName.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationFullName.java
new file mode 100644
index 0000000000..0d810cd82a
--- /dev/null
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationFullName.java
@@ -0,0 +1,28 @@
+/*
+ * 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.server.authorization.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AuthorizationFullName {}
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationObjectType.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationObjectType.java
new file mode 100644
index 0000000000..7a9e36009b
--- /dev/null
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationObjectType.java
@@ -0,0 +1,28 @@
+/*
+ * 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.server.authorization.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AuthorizationObjectType {}
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
b/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
index 58ca5b89cf..b261036ec7 100644
---
a/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
+++
b/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
@@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.PathParam;
@@ -36,10 +37,14 @@ import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Entity;
import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.authorization.AuthorizationRequestContext;
+import org.apache.gravitino.server.authorization.MetadataFilterHelper;
import
org.apache.gravitino.server.authorization.annotations.AuthorizationExpression;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationFullName;
import
org.apache.gravitino.server.authorization.annotations.AuthorizationMetadata;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationObjectType;
import
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
import org.apache.gravitino.server.web.Utils;
import org.apache.gravitino.server.web.rest.CatalogOperations;
@@ -51,9 +56,11 @@ import org.apache.gravitino.server.web.rest.OwnerOperations;
import org.apache.gravitino.server.web.rest.PermissionOperations;
import org.apache.gravitino.server.web.rest.RoleOperations;
import org.apache.gravitino.server.web.rest.SchemaOperations;
+import org.apache.gravitino.server.web.rest.StatisticOperations;
import org.apache.gravitino.server.web.rest.TableOperations;
import org.apache.gravitino.server.web.rest.TopicOperations;
import org.apache.gravitino.server.web.rest.UserOperations;
+import org.apache.gravitino.utils.MetadataObjectUtil;
import org.apache.gravitino.utils.NameIdentifierUtil;
import org.apache.gravitino.utils.PrincipalUtils;
import org.glassfish.hk2.api.Descriptor;
@@ -84,7 +91,8 @@ public class GravitinoInterceptionService implements
InterceptionService {
GroupOperations.class.getName(),
PermissionOperations.class.getName(),
RoleOperations.class.getName(),
- OwnerOperations.class.getName()));
+ OwnerOperations.class.getName(),
+ StatisticOperations.class.getName()));
}
@Override
@@ -192,6 +200,7 @@ public class GravitinoInterceptionService implements
InterceptionService {
Parameter[] parameters, Object[] args) {
Map<Entity.EntityType, String> entities = new HashMap<>();
Map<Entity.EntityType, NameIdentifier> nameIdentifierMap = new
HashMap<>();
+ // Extract AuthorizationMetadata
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
AuthorizationMetadata authorizeResource =
@@ -202,12 +211,31 @@ public class GravitinoInterceptionService implements
InterceptionService {
Entity.EntityType type = authorizeResource.type();
entities.put(type, String.valueOf(args[i]));
}
+
String metalake = entities.get(Entity.EntityType.METALAKE);
String catalog = entities.get(Entity.EntityType.CATALOG);
String schema = entities.get(Entity.EntityType.SCHEMA);
String table = entities.get(Entity.EntityType.TABLE);
String topic = entities.get(Entity.EntityType.TOPIC);
String fileset = entities.get(Entity.EntityType.FILESET);
+
+ // Extract full name and types
+ String fullName = null;
+ String metadataObjectType = null;
+ for (int i = 0; i < parameters.length; i++) {
+ Parameter parameter = parameters[i];
+ AuthorizationFullName authorizeFullName =
+ parameter.getAnnotation(AuthorizationFullName.class);
+ if (authorizeFullName != null) {
+ fullName = String.valueOf(args[i]);
+ }
+
+ AuthorizationObjectType objectType =
parameter.getAnnotation(AuthorizationObjectType.class);
+ if (objectType != null) {
+ metadataObjectType = String.valueOf(args[i]);
+ }
+ }
+
entities.forEach(
(type, metadata) -> {
switch (type) {
@@ -264,6 +292,18 @@ public class GravitinoInterceptionService implements
InterceptionService {
break;
}
});
+
+ // Extract fullName and metadataObjectType
+ if (fullName != null && metadataObjectType != null && metalake != null) {
+ MetadataObject.Type type =
+
MetadataObject.Type.valueOf(metadataObjectType.toUpperCase(Locale.ROOT));
+ NameIdentifier nameIdentifier =
+ MetadataObjectUtil.toEntityIdent(metalake,
MetadataObjects.parse(fullName, type));
+ nameIdentifierMap.putAll(
+ MetadataFilterHelper.spiltMetadataNames(
+ metalake, MetadataObjectUtil.toEntityType(type),
nameIdentifier));
+ }
+
return nameIdentifierMap;
}
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/rest/StatisticOperations.java
b/server/src/main/java/org/apache/gravitino/server/web/rest/StatisticOperations.java
index 9e9dbdbe65..76426cdb7d 100644
---
a/server/src/main/java/org/apache/gravitino/server/web/rest/StatisticOperations.java
+++
b/server/src/main/java/org/apache/gravitino/server/web/rest/StatisticOperations.java
@@ -42,6 +42,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
+import org.apache.gravitino.Entity;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.dto.requests.PartitionStatisticsDropRequest;
@@ -58,6 +59,10 @@ import
org.apache.gravitino.dto.stats.PartitionStatisticsUpdateDTO;
import org.apache.gravitino.dto.util.DTOConverters;
import org.apache.gravitino.exceptions.IllegalStatisticNameException;
import org.apache.gravitino.metrics.MetricNames;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationExpression;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationFullName;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationMetadata;
+import
org.apache.gravitino.server.authorization.annotations.AuthorizationObjectType;
import org.apache.gravitino.server.web.Utils;
import org.apache.gravitino.stats.PartitionRange;
import org.apache.gravitino.stats.PartitionStatistics;
@@ -89,10 +94,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "list-stats." + MetricNames.HTTP_PROCESS_DURATION, absolute =
true)
@ResponseMetered(name = "list-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_SELECT_TABLE|| ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response listStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName) {
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName) {
LOG.info(
"Received list statistics request for object full name: {} type: {} in
the metalake {}",
fullName,
@@ -127,10 +139,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "update-stats." + MetricNames.HTTP_PROCESS_DURATION, absolute
= true)
@ResponseMetered(name = "update-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response updateStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName,
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName,
StatisticsUpdateRequest request) {
try {
LOG.info(
@@ -177,10 +196,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "drop-stats." + MetricNames.HTTP_PROCESS_DURATION, absolute =
true)
@ResponseMetered(name = "drop-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response dropStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName,
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName,
StatisticsDropRequest request) {
try {
LOG.info(
@@ -219,10 +245,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "list-partition-stats." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
@ResponseMetered(name = "list-partition-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_SELECT_TABLE|| ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response listPartitionStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName,
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName,
@QueryParam("from") String fromPartitionName,
@QueryParam("to") String toPartitionName,
@QueryParam("fromInclusive") @DefaultValue("true") boolean fromInclusive,
@@ -305,10 +338,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "update-partitions-stats." +
MetricNames.HTTP_PROCESS_DURATION, absolute = true)
@ResponseMetered(name = "update-partitions-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response updatePartitionStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName,
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName,
PartitionStatisticsUpdateRequest request) {
LOG.info("Updating partition statistics for table: {} in the metalake {}",
fullName, metalake);
try {
@@ -377,10 +417,17 @@ public class StatisticOperations {
@Produces("application/vnd.gravitino.v1+json")
@Timed(name = "drop-partitions-stats." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
@ResponseMetered(name = "drop-partitions-stats", absolute = true)
+ @AuthorizationExpression(
+ expression =
+ "ANY(OWNER, METALAKE, CATALOG) || "
+ + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+ + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER ||
ANY_MODIFY_TABLE)",
+ accessMetadataType = MetadataObject.Type.TABLE)
public Response dropPartitionStatistics(
- @PathParam("metalake") String metalake,
- @PathParam("type") String type,
- @PathParam("fullName") String fullName,
+ @PathParam("metalake") @AuthorizationMetadata(type =
Entity.EntityType.METALAKE)
+ String metalake,
+ @PathParam("type") @AuthorizationObjectType String type,
+ @PathParam("fullName") @AuthorizationFullName String fullName,
PartitionStatisticsDropRequest request) {
try {