This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-0.7
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-0.7 by this push:
new b913e9846 [#5124][#5146] feat(auth-ranger): Ranger plugin should
support rename operation (#5375)
b913e9846 is described below
commit b913e984693abcca026da1ba4d792ff359ceb125
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Oct 31 11:06:03 2024 +0800
[#5124][#5146] feat(auth-ranger): Ranger plugin should support rename
operation (#5375)
### What changes were proposed in this pull request?
Add rename a securable object in the RoleChange.
### Why are the changes needed?
Fix: #5124 #5146
### Does this PR introduce _any_ user-facing change?
N/A
### How was this patch tested?
Add ITs.
Co-authored-by: Xun <[email protected]>
---
.../workflows/access-control-integration-test.yml | 6 +-
.../authorization/MetadataObjectChange.java | 181 +++++++++++
.../ranger/RangerAuthorizationHivePlugin.java | 58 +++-
.../ranger/RangerAuthorizationPlugin.java | 341 +++++++++++++++++++-
.../authorization/ranger/RangerHelper.java | 113 +++----
.../ranger/RangerMetadataObjects.java | 7 +-
.../ranger/RangerPrivilegesMappingProvider.java | 15 +
.../test/RangerAuthorizationPluginIT.java | 39 ++-
.../ranger/integration/test/RangerHiveE2EIT.java | 3 +-
.../ranger/integration/test/RangerHiveIT.java | 343 +++++++++++++++++++--
.../ranger/integration/test/RangerITEnv.java | 32 +-
.../authorization/AuthorizationPlugin.java | 5 +-
...lugin.java => MetadataAuthorizationPlugin.java} | 20 +-
.../mysql/TestMySQLAuthorizationPlugin.java | 6 +
.../ranger/TestRangerAuthorizationPlugin.java | 6 +
15 files changed, 1056 insertions(+), 119 deletions(-)
diff --git a/.github/workflows/access-control-integration-test.yml
b/.github/workflows/access-control-integration-test.yml
index ad347aa7e..54ffde2ee 100644
--- a/.github/workflows/access-control-integration-test.yml
+++ b/.github/workflows/access-control-integration-test.yml
@@ -87,9 +87,9 @@ jobs:
- name: Authorization Integration Test (JDK${{ matrix.java-version }})
id: integrationTest
run: |
- ./gradlew -PtestMode=embedded -PjdbcBackend=h2 -PjdkVersion=${{
matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test --tests
"org.apache.gravitino.authorization.ranger.**"
- ./gradlew -PtestMode=deploy -PjdbcBackend=mysql -PjdkVersion=${{
matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test --tests
"org.apache.gravitino.authorization.ranger.**"
- ./gradlew -PtestMode=deploy -PjdbcBackend=postgresql
-PjdkVersion=${{ matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test --tests
"org.apache.gravitino.authorization.ranger.**"
+ ./gradlew -PtestMode=embedded -PjdbcBackend=h2 -PjdkVersion=${{
matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test
+ ./gradlew -PtestMode=deploy -PjdbcBackend=mysql -PjdkVersion=${{
matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test
+ ./gradlew -PtestMode=deploy -PjdbcBackend=postgresql
-PjdkVersion=${{ matrix.java-version }} -PskipDockerTests=false
:authorizations:authorization-ranger:test
- name: Upload integrate tests reports
uses: actions/upload-artifact@v3
diff --git
a/api/src/main/java/org/apache/gravitino/authorization/MetadataObjectChange.java
b/api/src/main/java/org/apache/gravitino/authorization/MetadataObjectChange.java
new file mode 100644
index 000000000..a7281d97d
--- /dev/null
+++
b/api/src/main/java/org/apache/gravitino/authorization/MetadataObjectChange.java
@@ -0,0 +1,181 @@
+/*
+ * 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.authorization;
+
+import com.google.common.base.Preconditions;
+import java.util.Objects;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.Evolving;
+
+/**
+ * The MetadataObjectChange interface defines the public API for managing
roles in an authorization.
+ */
+@Evolving
+public interface MetadataObjectChange {
+ /**
+ * Rename a metadata entity MetadataObjectChange.
+ *
+ * @param metadataObject The metadata object.
+ * @param newMetadataObject The new metadata object.
+ * @return return a MetadataObjectChange for the rename metadata object.
+ */
+ static MetadataObjectChange rename(
+ MetadataObject metadataObject, MetadataObject newMetadataObject) {
+ return new RenameMetadataObject(metadataObject, newMetadataObject);
+ }
+
+ /**
+ * Remove a metadata entity MetadataObjectChange.
+ *
+ * @param metadataObject The metadata object.
+ * @return return a MetadataObjectChange for the remove metadata object.
+ */
+ static MetadataObjectChange remove(MetadataObject metadataObject) {
+ return new RemoveMetadataObject(metadataObject);
+ }
+
+ /** A RenameMetadataObject is to rename securable object's metadata entity.
*/
+ final class RenameMetadataObject implements MetadataObjectChange {
+ private final MetadataObject metadataObject;
+ private final MetadataObject newMetadataObject;
+
+ private RenameMetadataObject(MetadataObject metadataObject, MetadataObject
newMetadataObject) {
+ Preconditions.checkArgument(
+ !metadataObject.fullName().equals(newMetadataObject.fullName()),
+ "The metadata object must be different!");
+ Preconditions.checkArgument(
+ metadataObject.type().equals(newMetadataObject.type()),
+ "The metadata object type must be same!");
+
+ this.metadataObject = metadataObject;
+ this.newMetadataObject = newMetadataObject;
+ }
+
+ /**
+ * Returns the metadataObject to be renamed.
+ *
+ * @return return a metadataObject.
+ */
+ public MetadataObject metadataObject() {
+ return metadataObject;
+ }
+
+ /**
+ * Returns the new metadataObject object.
+ *
+ * @return return a metadataObject object.
+ */
+ public MetadataObject newMetadataObject() {
+ return newMetadataObject;
+ }
+
+ /**
+ * Compares this RenameMetadataObject instance with another object for
equality. The comparison
+ * is based on the old metadata entity and new metadata entity.
+ *
+ * @param o The object to compare with this instance.
+ * @return true if the given object represents the same rename metadata
entity; false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RenameMetadataObject that = (RenameMetadataObject) o;
+ return metadataObject.equals(that.metadataObject)
+ && newMetadataObject.equals(that.newMetadataObject);
+ }
+
+ /**
+ * Generates a hash code for this RenameMetadataObject instance. The hash
code is based on the
+ * old metadata entity and new metadata entity.
+ *
+ * @return A hash code value for this update metadata entity operation.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(metadataObject, newMetadataObject);
+ }
+
+ /**
+ * Returns a string representation of the RenameMetadataObject instance.
This string format
+ * includes the class name followed by the update metadata entity object
operation.
+ *
+ * @return A string representation of the RenameMetadataObject instance.
+ */
+ @Override
+ public String toString() {
+ return "RENAMEMETADATAOBJECT " + metadataObject + " " +
newMetadataObject;
+ }
+ }
+
+ /** A RemoveMetadataObject is to remove securable object's metadata entity.
*/
+ final class RemoveMetadataObject implements MetadataObjectChange {
+ private final MetadataObject metadataObject;
+
+ private RemoveMetadataObject(MetadataObject metadataObject) {
+ this.metadataObject = metadataObject;
+ }
+
+ /**
+ * Returns the metadataObject to be renamed.
+ *
+ * @return return a metadataObject.
+ */
+ public MetadataObject metadataObject() {
+ return metadataObject;
+ }
+
+ /**
+ * Compares this RemoveMetadataObject instance with another object for
equality. The comparison
+ * is based on the old metadata entity.
+ *
+ * @param o The object to compare with this instance.
+ * @return true if the given object represents the same rename metadata
entity; false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RenameMetadataObject that = (RenameMetadataObject) o;
+ return metadataObject.equals(that.metadataObject);
+ }
+
+ /**
+ * Generates a hash code for this RemoveMetadataObject instance. The hash
code is based on the
+ * old metadata entity.
+ *
+ * @return A hash code value for this update metadata entity operation.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(metadataObject);
+ }
+
+ /**
+ * Returns a string representation of the RemoveMetadataObject instance.
This string format
+ * includes the class name followed by the remove metadata entity object
operation.
+ *
+ * @return A string representation of the RemoveMetadataObject instance.
+ */
+ @Override
+ public String toString() {
+ return "REMOVEMETADATAOBJECT " + metadataObject;
+ }
+ }
+}
diff --git
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationHivePlugin.java
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationHivePlugin.java
index c88f57f8e..12072d7f6 100644
---
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationHivePlugin.java
+++
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationHivePlugin.java
@@ -138,7 +138,23 @@ public class RangerAuthorizationHivePlugin extends
RangerAuthorizationPlugin {
Privilege.Name.SELECT_TABLE);
}
+ /**
+ * Allow Gravitino MetadataObject type defines rule.
+ *
+ * @return The allow Gravitino MetadataObject type defines rule.
+ */
+ @Override
+ public Set<MetadataObject.Type> allowMetadataObjectTypesRule() {
+ return ImmutableSet.of(
+ MetadataObject.Type.METALAKE,
+ MetadataObject.Type.CATALOG,
+ MetadataObject.Type.SCHEMA,
+ MetadataObject.Type.TABLE,
+ MetadataObject.Type.COLUMN);
+ }
+
/** Translate the Gravitino securable object to the Ranger owner securable
object. */
+ @Override
public List<RangerSecurableObject> translateOwner(MetadataObject
gravitinoMetadataObject) {
List<RangerSecurableObject> rangerSecurableObjects = new ArrayList<>();
@@ -195,14 +211,14 @@ public class RangerAuthorizationHivePlugin extends
RangerAuthorizationPlugin {
// Add `{schema}.{table}` for the TABLE permission
rangerSecurableObjects.add(
generateRangerSecurableObject(
- convertToRangerMetadataObject(gravitinoMetadataObject),
+ translateMetadataObject(gravitinoMetadataObject).names(),
RangerMetadataObject.Type.TABLE,
ownerMappingRule()));
// Add `{schema}.{table}.*` for the COLUMN permission
rangerSecurableObjects.add(
generateRangerSecurableObject(
Stream.concat(
-
convertToRangerMetadataObject(gravitinoMetadataObject).stream(),
+
translateMetadataObject(gravitinoMetadataObject).names().stream(),
Stream.of(RangerHelper.RESOURCE_ALL))
.collect(Collectors.toList()),
RangerMetadataObject.Type.COLUMN,
@@ -218,6 +234,7 @@ public class RangerAuthorizationHivePlugin extends
RangerAuthorizationPlugin {
}
/** Translate the Gravitino securable object to the Ranger securable object.
*/
+ @Override
public List<RangerSecurableObject> translatePrivilege(SecurableObject
securableObject) {
List<RangerSecurableObject> rangerSecurableObjects = new ArrayList<>();
@@ -352,14 +369,14 @@ public class RangerAuthorizationHivePlugin extends
RangerAuthorizationPlugin {
// Add `{schema}.{table}` for the TABLE permission
rangerSecurableObjects.add(
generateRangerSecurableObject(
- convertToRangerMetadataObject(securableObject),
+
translateMetadataObject(securableObject).names(),
RangerMetadataObject.Type.TABLE,
rangerPrivileges));
// Add `{schema}.{table}.*` for the COLUMN permission
rangerSecurableObjects.add(
generateRangerSecurableObject(
Stream.concat(
-
convertToRangerMetadataObject(securableObject).stream(),
+
translateMetadataObject(securableObject).names().stream(),
Stream.of(RangerHelper.RESOURCE_ALL))
.collect(Collectors.toList()),
RangerMetadataObject.Type.COLUMN,
@@ -385,16 +402,39 @@ public class RangerAuthorizationHivePlugin extends
RangerAuthorizationPlugin {
}
/**
- * Because the Ranger securable object is different from the Gravitino
securable object, we need
- * to convert the Gravitino securable object to the Ranger securable object.
+ * Because the Ranger metadata object is different from the Gravitino
metadata object, we need to
+ * convert the Gravitino metadata object to the Ranger metadata object.
*/
- List<String> convertToRangerMetadataObject(MetadataObject metadataObject) {
+ @Override
+ public RangerMetadataObject translateMetadataObject(MetadataObject
metadataObject) {
+ Preconditions.checkArgument(
+ allowMetadataObjectTypesRule().contains(metadataObject.type()),
+ String.format(
+ "The metadata object type %s is not supported in the
RangerAuthorizationHivePlugin",
+ metadataObject.type()));
Preconditions.checkArgument(
!(metadataObject instanceof RangerPrivileges),
"The metadata object must be not a RangerPrivileges object.");
List<String> nsMetadataObject =
Lists.newArrayList(SecurableObjects.DOT_SPLITTER.splitToList(metadataObject.fullName()));
- nsMetadataObject.remove(0); // remove the catalog name
- return nsMetadataObject;
+ Preconditions.checkArgument(
+ nsMetadataObject.size() > 0, "The metadata object must have at least
one name.");
+
+ RangerMetadataObject.Type type;
+ if (metadataObject.type() == MetadataObject.Type.METALAKE
+ || metadataObject.type() == MetadataObject.Type.CATALOG) {
+ nsMetadataObject.clear();
+ nsMetadataObject.add(RangerHelper.RESOURCE_ALL);
+ type = RangerMetadataObject.Type.SCHEMA;
+ } else {
+ nsMetadataObject.remove(0); // Remove the catalog name
+ type = RangerMetadataObject.Type.fromMetadataType(metadataObject.type());
+ }
+
+ validateRangerMetadataObject(nsMetadataObject, type);
+ return new RangerMetadataObjects.RangerMetadataObjectImpl(
+ RangerMetadataObjects.getParentFullName(nsMetadataObject),
+ RangerMetadataObjects.getLastName(nsMetadataObject),
+ type);
}
}
diff --git
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java
index 965c7df31..ff26d1ca6 100644
---
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java
+++
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java
@@ -18,20 +18,29 @@
*/
package org.apache.gravitino.authorization.ranger;
+import static
org.apache.gravitino.authorization.ranger.RangerMetadataObjects.DOT_JOINER;
+import static
org.apache.gravitino.authorization.ranger.RangerMetadataObjects.DOT_SPLITTER;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import java.io.IOException;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.MetadataObjectChange;
import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Privilege;
import org.apache.gravitino.authorization.Role;
@@ -222,6 +231,38 @@ public abstract class RangerAuthorizationPlugin
return Boolean.TRUE;
}
+ @Override
+ public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws
RuntimeException {
+ for (MetadataObjectChange change : changes) {
+ if (change instanceof MetadataObjectChange.RenameMetadataObject) {
+ MetadataObject metadataObject =
+ ((MetadataObjectChange.RenameMetadataObject)
change).metadataObject();
+ MetadataObject newMetadataObject =
+ ((MetadataObjectChange.RenameMetadataObject)
change).newMetadataObject();
+ RangerMetadataObject rangerMetadataObject =
translateMetadataObject(metadataObject);
+ RangerMetadataObject newRangerMetadataObject =
translateMetadataObject(newMetadataObject);
+ if (rangerMetadataObject.equals(newRangerMetadataObject)) {
+ LOG.info(
+ "The metadata object({}) and new metadata object({}) are equal,
so ignore rename!",
+ rangerMetadataObject.fullName(),
+ newRangerMetadataObject.fullName());
+ continue;
+ }
+ doRenameMetadataObject(rangerMetadataObject, newRangerMetadataObject);
+ } else if (change instanceof MetadataObjectChange.RemoveMetadataObject) {
+ MetadataObject metadataObject =
+ ((MetadataObjectChange.RemoveMetadataObject)
change).metadataObject();
+ RangerMetadataObject rangerMetadataObject =
translateMetadataObject(metadataObject);
+ doRemoveMetadataObject(rangerMetadataObject);
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported metadata object change type: "
+ + (change == null ? "null" :
change.getClass().getSimpleName()));
+ }
+ }
+ return Boolean.TRUE;
+ }
+
/**
* Set or transfer the ownership of the metadata object. <br>
* 1. If the metadata object already has an owner, then transfer the
ownership from preOwner to
@@ -704,20 +745,314 @@ public abstract class RangerAuthorizationPlugin
}
}
+ /**
+ * IF remove the SCHEMA, need to remove these the relevant policies,
`{schema}`, `{schema}.*`,
+ * `{schema}.*.*` <br>
+ * IF remove the TABLE, need to remove these the relevant policies,
`{schema}.*`, `{schema}.*.*`
+ * <br>
+ * IF remove the COLUMN, Only need to remove `{schema}.*.*` <br>
+ */
+ private void doRemoveMetadataObject(RangerMetadataObject
rangerMetadataObject) {
+ switch (rangerMetadataObject.type()) {
+ case SCHEMA:
+ doRemoveSchemaMetadataObject(rangerMetadataObject);
+ break;
+ case TABLE:
+ doRemoveTableMetadataObject(rangerMetadataObject);
+ break;
+ case COLUMN:
+ removePolicyByMetadataObject(rangerMetadataObject.names());
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported metadata object type: " +
rangerMetadataObject.type());
+ }
+ }
+
+ /**
+ * Remove the SCHEMA, Need to remove these the relevant policies,
`{schema}`, `{schema}.*`,
+ * `{schema}.*.*` permissions.
+ */
+ private void doRemoveSchemaMetadataObject(RangerMetadataObject
rangerMetadataObject) {
+ Preconditions.checkArgument(
+ rangerMetadataObject.type() == RangerMetadataObject.Type.SCHEMA,
+ "The metadata object type must be SCHEMA");
+ Preconditions.checkArgument(
+ rangerMetadataObject.names().size() == 1, "The metadata object names
must be 1");
+ if (RangerHelper.RESOURCE_ALL.equals(rangerMetadataObject.name())) {
+ // Delete metalake or catalog policies in this Ranger service
+ try {
+ List<RangerPolicy> policies =
rangerClient.getPoliciesInService(rangerServiceName);
+ policies.stream()
+ .forEach(
+ policy -> {
+ try {
+ rangerClient.deletePolicy(policy.getId());
+ } catch (RangerServiceException e) {
+ LOG.error("Failed to rename the policy {}!", policy);
+ throw new RuntimeException(e);
+ }
+ });
+ } catch (RangerServiceException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ List<List<String>> loop =
+ ImmutableList.of(
+ ImmutableList.of(rangerMetadataObject.name())
+ /** SCHEMA permission */
+ ,
+ ImmutableList.of(rangerMetadataObject.name(),
RangerHelper.RESOURCE_ALL)
+ /** TABLE permission */
+ ,
+ ImmutableList.of(
+ rangerMetadataObject.name(), RangerHelper.RESOURCE_ALL,
RangerHelper.RESOURCE_ALL)
+ /** COLUMN permission */
+ );
+ for (List<String> resNames : loop) {
+ removePolicyByMetadataObject(resNames);
+ }
+ }
+ }
+
+ /**
+ * Remove the TABLE, Need to remove these the relevant policies,
`*.{table}`, `*.{table}.{column}`
+ * permissions.
+ */
+ private void doRemoveTableMetadataObject(RangerMetadataObject
rangerMetadataObject) {
+ List<List<String>> loop =
+ ImmutableList.of(
+ rangerMetadataObject.names()
+ /** TABLE permission */
+ ,
+ Stream.concat(
+ rangerMetadataObject.names().stream(),
Stream.of(RangerHelper.RESOURCE_ALL))
+ .collect(Collectors.toList())
+ /** COLUMN permission */
+ );
+ for (List<String> resNames : loop) {
+ removePolicyByMetadataObject(resNames);
+ }
+ }
+
+ /**
+ * IF rename the SCHEMA, Need to rename these the relevant policies,
`{schema}`, `{schema}.*`,
+ * `{schema}.*.*` <br>
+ * IF rename the TABLE, Need to rename these the relevant policies,
`{schema}.*`, `{schema}.*.*`
+ * <br>
+ * IF rename the COLUMN, Only need to rename `{schema}.*.*` <br>
+ */
+ private void doRenameMetadataObject(
+ RangerMetadataObject rangerMetadataObject, RangerMetadataObject
newRangerMetadataObject) {
+ switch (rangerMetadataObject.type()) {
+ case SCHEMA:
+ doRenameSchemaMetadataObject(rangerMetadataObject,
newRangerMetadataObject);
+ break;
+ case TABLE:
+ doRenameTableMetadataObject(rangerMetadataObject,
newRangerMetadataObject);
+ break;
+ case COLUMN:
+ doRenameColumnMetadataObject(rangerMetadataObject,
newRangerMetadataObject);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported metadata object type: " +
rangerMetadataObject.type());
+ }
+ }
+
+ /**
+ * Rename the SCHEMA, Need to rename these the relevant policies,
`{schema}`, `{schema}.*`,
+ * `{schema}.*.*` <br>
+ */
+ private void doRenameSchemaMetadataObject(
+ RangerMetadataObject rangerMetadataObject, RangerMetadataObject
newRangerMetadataObject) {
+ List<String> oldMetadataNames = new ArrayList<>();
+ List<String> newMetadataNames = new ArrayList<>();
+ List<Map<String, String>> loop =
+ ImmutableList.of(
+ ImmutableMap.of(
+ rangerMetadataObject.names().get(0),
newRangerMetadataObject.names().get(0)),
+ ImmutableMap.of(RangerHelper.RESOURCE_ALL,
RangerHelper.RESOURCE_ALL),
+ ImmutableMap.of(RangerHelper.RESOURCE_ALL,
RangerHelper.RESOURCE_ALL));
+ for (Map<String, String> mapName : loop) {
+ oldMetadataNames.add(mapName.keySet().stream().findFirst().get());
+ newMetadataNames.add(mapName.values().stream().findFirst().get());
+ updatePolicyByMetadataObject(MetadataObject.Type.SCHEMA,
oldMetadataNames, newMetadataNames);
+ }
+ }
+
+ /**
+ * Rename the TABLE, Need to rename these the relevant policies,
`*.{table}`, `*.{table}.{column}`
+ * <br>
+ */
+ private void doRenameTableMetadataObject(
+ RangerMetadataObject rangerMetadataObject, RangerMetadataObject
newRangerMetadataObject) {
+ List<String> oldMetadataNames = new ArrayList<>();
+ List<String> newMetadataNames = new ArrayList<>();
+ List<Map<String, MetadataObject.Type>> loop =
+ ImmutableList.of(
+ ImmutableMap.of(rangerMetadataObject.names().get(0),
MetadataObject.Type.SCHEMA),
+ ImmutableMap.of(rangerMetadataObject.names().get(1),
MetadataObject.Type.TABLE),
+ ImmutableMap.of(RangerHelper.RESOURCE_ALL,
MetadataObject.Type.COLUMN));
+ for (Map<String, MetadataObject.Type> nameAndType : loop) {
+ oldMetadataNames.add(nameAndType.keySet().stream().findFirst().get());
+ if (nameAndType.containsValue(MetadataObject.Type.SCHEMA)) {
+ newMetadataNames.add(newRangerMetadataObject.names().get(0));
+ // Skip update the schema name operation
+ continue;
+ } else if (nameAndType.containsValue(MetadataObject.Type.TABLE)) {
+ newMetadataNames.add(newRangerMetadataObject.names().get(1));
+ } else if (nameAndType.containsValue(MetadataObject.Type.COLUMN)) {
+ newMetadataNames.add(RangerHelper.RESOURCE_ALL);
+ }
+ updatePolicyByMetadataObject(MetadataObject.Type.TABLE,
oldMetadataNames, newMetadataNames);
+ }
+ }
+
+ /** rename the COLUMN, Only need to rename `*.*.{column}` <br> */
+ private void doRenameColumnMetadataObject(
+ RangerMetadataObject rangerMetadataObject, RangerMetadataObject
newRangerMetadataObject) {
+ List<String> oldMetadataNames = new ArrayList<>();
+ List<String> newMetadataNames = new ArrayList<>();
+ List<Map<String, MetadataObject.Type>> loop =
+ ImmutableList.of(
+ ImmutableMap.of(rangerMetadataObject.names().get(0),
MetadataObject.Type.SCHEMA),
+ ImmutableMap.of(rangerMetadataObject.names().get(1),
MetadataObject.Type.TABLE),
+ ImmutableMap.of(rangerMetadataObject.names().get(2),
MetadataObject.Type.COLUMN));
+ for (Map<String, MetadataObject.Type> nameAndType : loop) {
+ oldMetadataNames.add(nameAndType.keySet().stream().findFirst().get());
+ if (nameAndType.containsValue(MetadataObject.Type.SCHEMA)) {
+ newMetadataNames.add(newRangerMetadataObject.names().get(0));
+ // Skip update the schema name operation
+ continue;
+ } else if (nameAndType.containsValue(MetadataObject.Type.TABLE)) {
+ newMetadataNames.add(newRangerMetadataObject.names().get(1));
+ // Skip update the table name operation
+ continue;
+ } else if (nameAndType.containsValue(MetadataObject.Type.COLUMN)) {
+ newMetadataNames.add(newRangerMetadataObject.names().get(2));
+ }
+ updatePolicyByMetadataObject(MetadataObject.Type.COLUMN,
oldMetadataNames, newMetadataNames);
+ }
+ }
+
+ /**
+ * Remove the policy by the metadata object names. <br>
+ *
+ * @param metadataNames The metadata object names.
+ */
+ private void removePolicyByMetadataObject(List<String> metadataNames) {
+ List<RangerPolicy> policies =
rangerHelper.wildcardSearchPolies(metadataNames);
+ Map<String, String> preciseFilters = new HashMap<>();
+ for (int i = 0; i < metadataNames.size(); i++) {
+ preciseFilters.put(rangerHelper.policyResourceDefines.get(i),
metadataNames.get(i));
+ }
+ policies =
+ policies.stream()
+ .filter(
+ policy ->
+ policy.getResources().entrySet().stream()
+ .allMatch(
+ entry ->
+ preciseFilters.containsKey(entry.getKey())
+ && entry.getValue().getValues().size() == 1
+ && entry
+ .getValue()
+ .getValues()
+
.contains(preciseFilters.get(entry.getKey()))))
+ .collect(Collectors.toList());
+ policies.stream()
+ .forEach(
+ policy -> {
+ try {
+ rangerClient.deletePolicy(policy.getId());
+ } catch (RangerServiceException e) {
+ LOG.error("Failed to rename the policy {}!", policy);
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ private void updatePolicyByMetadataObject(
+ MetadataObject.Type operationType,
+ List<String> oldMetadataNames,
+ List<String> newMetadataNames) {
+ List<RangerPolicy> oldPolicies =
rangerHelper.wildcardSearchPolies(oldMetadataNames);
+ List<RangerPolicy> existNewPolicies =
rangerHelper.wildcardSearchPolies(newMetadataNames);
+ if (oldPolicies.isEmpty()) {
+ LOG.warn("Cannot find the Ranger policy for the metadata object({})!",
oldMetadataNames);
+ }
+ if (!existNewPolicies.isEmpty()) {
+ LOG.warn("The Ranger policy for the metadata object({}) already
exists!", newMetadataNames);
+ }
+ Map<MetadataObject.Type, Integer> operationTypeIndex =
+ ImmutableMap.of(
+ MetadataObject.Type.SCHEMA, 0,
+ MetadataObject.Type.TABLE, 1,
+ MetadataObject.Type.COLUMN, 2);
+ oldPolicies.stream()
+ .forEach(
+ policy -> {
+ try {
+ // Update the policy name
+ String policyName = policy.getName();
+ List<String> policyNames =
Lists.newArrayList(DOT_SPLITTER.splitToList(policyName));
+ Preconditions.checkArgument(
+ policyNames.size() >= oldMetadataNames.size(),
+ String.format("The policy name(%s) is invalid!",
policyName));
+ int index = operationTypeIndex.get(operationType);
+ if (policyNames.get(index).equals(RangerHelper.RESOURCE_ALL)) {
+ // Doesn't need to rename the policy `*`
+ return;
+ }
+ policyNames.set(index, newMetadataNames.get(index));
+ // Update the policy resource name to new name
+ policy
+ .getResources()
+ .put(
+ rangerHelper.policyResourceDefines.get(index),
+ new
RangerPolicy.RangerPolicyResource(newMetadataNames.get(index)));
+ policy.setName(DOT_JOINER.join(policyNames));
+
+ boolean alreadyExist =
+ existNewPolicies.stream()
+ .anyMatch(
+ existNewPolicy ->
+
existNewPolicy.getName().equals(policy.getName())
+ ||
existNewPolicy.getResources().equals(policy.getResources()));
+ if (alreadyExist) {
+ LOG.warn(
+ "The Ranger policy for the metadata object({}) already
exists!",
+ newMetadataNames);
+ return;
+ }
+
+ // Update the policy
+ rangerClient.updatePolicy(policy.getId(), policy);
+ } catch (RangerServiceException e) {
+ LOG.error("Failed to rename the policy {}!", policy);
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
@Override
public void close() throws IOException {}
- /** Generate different Ranger securable object */
+ /** Generate Ranger securable object */
public RangerSecurableObject generateRangerSecurableObject(
List<String> names, RangerMetadataObject.Type type, Set<RangerPrivilege>
privileges) {
validateRangerMetadataObject(names, type);
- RangerMetadataObject metadataObject =
+ RangerMetadataObject rangerMetadataObject =
new RangerMetadataObjects.RangerMetadataObjectImpl(
RangerMetadataObjects.getParentFullName(names),
RangerMetadataObjects.getLastName(names),
type);
return new RangerSecurableObjects.RangerSecurableObjectImpl(
- metadataObject.parent(), metadataObject.name(), metadataObject.type(),
privileges);
+ rangerMetadataObject.parent(),
+ rangerMetadataObject.name(),
+ rangerMetadataObject.type(),
+ privileges);
}
public boolean validAuthorizationOperation(List<SecurableObject>
securableObjects) {
diff --git
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java
index 51a61560f..86ed2ee88 100644
---
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java
+++
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java
@@ -53,7 +53,7 @@ public class RangerHelper {
/** The owner privileges, the owner can do anything on the metadata object */
private final Set<RangerPrivilege> ownerPrivileges;
/** The policy search keys */
- private final List<String> policyResourceDefines;
+ protected final List<String> policyResourceDefines;
private final RangerClient rangerClient;
private final String rangerAdminName;
@@ -163,72 +163,83 @@ public class RangerHelper {
}
/**
- * Find the managed policy for the ranger securable object.
+ * Find the managed policies for the ranger securable object.
*
- * @param rangerMetadataObject The ranger securable object to find the
managed policy.
+ * @param metadataNames The metadata object names to find the managed policy.
* @return The managed policy for the metadata object.
*/
- public RangerPolicy findManagedPolicy(RangerMetadataObject
rangerMetadataObject)
+ public List<RangerPolicy> wildcardSearchPolies(List<String> metadataNames)
throws AuthorizationPluginException {
- List<String> nsMetadataObj = rangerMetadataObject.names();
-
Map<String, String> searchFilters = new HashMap<>();
- Map<String, String> preciseFilters = new HashMap<>();
searchFilters.put(SearchFilter.SERVICE_NAME, rangerServiceName);
searchFilters.put(SearchFilter.POLICY_LABELS_PARTIAL,
MANAGED_BY_GRAVITINO);
- for (int i = 0; i < nsMetadataObj.size(); i++) {
+ for (int i = 0; i < metadataNames.size(); i++) {
searchFilters.put(
- SearchFilter.RESOURCE_PREFIX + policyResourceDefines.get(i),
nsMetadataObj.get(i));
- preciseFilters.put(policyResourceDefines.get(i), nsMetadataObj.get(i));
+ SearchFilter.RESOURCE_PREFIX + policyResourceDefines.get(i),
metadataNames.get(i));
}
try {
List<RangerPolicy> policies = rangerClient.findPolicies(searchFilters);
+ return policies;
+ } catch (RangerServiceException e) {
+ throw new AuthorizationPluginException(e);
+ }
+ }
- if (!policies.isEmpty()) {
- /**
- * Because Ranger doesn't support the precise search, Ranger will
return the policy meets
- * the wildcard(*,?) conditions, If you use `db.table` condition to
search policy, the
- * Ranger will match `db1.table1`, `db1.table2`, `db*.table*`, So we
need to manually
- * precisely filter this research results.
- */
- policies =
- policies.stream()
- .filter(
- policy ->
- policy.getResources().entrySet().stream()
- .allMatch(
- entry ->
- preciseFilters.containsKey(entry.getKey())
- && entry.getValue().getValues().size()
== 1
- && entry
- .getValue()
- .getValues()
-
.contains(preciseFilters.get(entry.getKey()))))
- .collect(Collectors.toList());
- }
-
- // Only return the policies that are managed by Gravitino.
- if (policies.size() > 1) {
- throw new AuthorizationPluginException(
- "Every metadata object has only a Gravitino managed policy.");
+ /**
+ * Find the managed policy for the ranger securable object.
+ *
+ * @param rangerMetadataObject The ranger securable object to find the
managed policy.
+ * @return The managed policy for the metadata object.
+ */
+ public RangerPolicy findManagedPolicy(RangerMetadataObject
rangerMetadataObject)
+ throws AuthorizationPluginException {
+ List<RangerPolicy> policies =
wildcardSearchPolies(rangerMetadataObject.names());
+ if (!policies.isEmpty()) {
+ /**
+ * Because Ranger doesn't support the precise search, Ranger will return
the policy meets the
+ * wildcard(*,?) conditions, If you use `db.table` condition to search
policy, the Ranger will
+ * match `db1.table1`, `db1.table2`, `db*.table*`, So we need to
manually precisely filter
+ * this research results.
+ */
+ List<String> nsMetadataObj = rangerMetadataObject.names();
+ Map<String, String> preciseFilters = new HashMap<>();
+ for (int i = 0; i < nsMetadataObj.size(); i++) {
+ preciseFilters.put(policyResourceDefines.get(i), nsMetadataObj.get(i));
}
+ policies =
+ policies.stream()
+ .filter(
+ policy ->
+ policy.getResources().entrySet().stream()
+ .allMatch(
+ entry ->
+ preciseFilters.containsKey(entry.getKey())
+ && entry.getValue().getValues().size()
== 1
+ && entry
+ .getValue()
+ .getValues()
+
.contains(preciseFilters.get(entry.getKey()))))
+ .collect(Collectors.toList());
+ }
+ // Only return the policies that are managed by Gravitino.
+ if (policies.size() > 1) {
+ throw new AuthorizationPluginException(
+ "Every metadata object has only a Gravitino managed policy.");
+ }
- if (policies.isEmpty()) {
- return null;
- }
+ if (policies.isEmpty()) {
+ return null;
+ }
- RangerPolicy policy = policies.get(0);
- // Delegating Gravitino management policies cannot contain duplicate
privilege
- policy.getPolicyItems().forEach(this::checkPolicyItemAccess);
- policy.getDenyPolicyItems().forEach(this::checkPolicyItemAccess);
- policy.getRowFilterPolicyItems().forEach(this::checkPolicyItemAccess);
- policy.getDataMaskPolicyItems().forEach(this::checkPolicyItemAccess);
+ RangerPolicy policy = policies.get(0);
+ // Delegating Gravitino management policies cannot contain duplicate
privilege
+ policy.getPolicyItems().forEach(this::checkPolicyItemAccess);
+ policy.getDenyPolicyItems().forEach(this::checkPolicyItemAccess);
+ policy.getRowFilterPolicyItems().forEach(this::checkPolicyItemAccess);
+ policy.getDataMaskPolicyItems().forEach(this::checkPolicyItemAccess);
- return policy;
- } catch (RangerServiceException e) {
- throw new AuthorizationPluginException(e);
- }
+ return policy;
}
protected boolean checkRangerRole(String roleName) throws
AuthorizationPluginException {
@@ -373,9 +384,7 @@ public class RangerHelper {
policy.setService(rangerServiceName);
policy.setName(metadataObject.fullName());
policy.setPolicyLabels(Lists.newArrayList(RangerHelper.MANAGED_BY_GRAVITINO));
-
List<String> nsMetadataObject = metadataObject.names();
-
for (int i = 0; i < nsMetadataObject.size(); i++) {
RangerPolicy.RangerPolicyResource policyResource =
new RangerPolicy.RangerPolicyResource(nsMetadataObject.get(i));
diff --git
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjects.java
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjects.java
index de2002df1..7c7bed69d 100644
---
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjects.java
+++
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjects.java
@@ -21,15 +21,14 @@ package org.apache.gravitino.authorization.ranger;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
import java.util.List;
import org.apache.gravitino.MetadataObject;
/** The helper class for {@link RangerMetadataObject}. */
public class RangerMetadataObjects {
- private static final Splitter DOT_SPLITTER = Splitter.on('.');
+ protected static final Splitter DOT_SPLITTER = Splitter.on('.');
- private static final Joiner DOT_JOINER = Joiner.on('.');
+ protected static final Joiner DOT_JOINER = Joiner.on('.');
private RangerMetadataObjects() {}
@@ -84,7 +83,7 @@ public class RangerMetadataObjects {
@Override
public List<String> names() {
- return Lists.newArrayList(DOT_SPLITTER.splitToList(fullName()));
+ return DOT_SPLITTER.splitToList(fullName());
}
@Override
diff --git
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilegesMappingProvider.java
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilegesMappingProvider.java
index 6b30b4bb1..ca11aaf70 100644
---
a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilegesMappingProvider.java
+++
b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilegesMappingProvider.java
@@ -59,6 +59,13 @@ public interface RangerPrivilegesMappingProvider {
*/
Set<Privilege.Name> allowPrivilegesRule();
+ /**
+ * Allow Gravitino MetadataObject type defines rule.
+ *
+ * @return The allow Gravitino MetadataObject type defines rule.
+ */
+ Set<MetadataObject.Type> allowMetadataObjectTypesRule();
+
/**
* Translate the Gravitino securable object to the Ranger securable object.
*
@@ -74,4 +81,12 @@ public interface RangerPrivilegesMappingProvider {
* @return The Ranger owner securable object list.
*/
List<RangerSecurableObject> translateOwner(MetadataObject metadataObject);
+
+ /**
+ * Translate the Gravitino metadata object to the Ranger metadata object.
+ *
+ * @param metadataObject The Gravitino metadata object.
+ * @return The Ranger metadata object.
+ */
+ RangerMetadataObject translateMetadataObject(MetadataObject metadataObject);
}
diff --git
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java
index 21ab5dc55..97f2b9035 100644
---
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java
+++
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java
@@ -29,6 +29,7 @@ import org.apache.gravitino.authorization.Privileges;
import org.apache.gravitino.authorization.SecurableObject;
import org.apache.gravitino.authorization.SecurableObjects;
import org.apache.gravitino.authorization.ranger.RangerAuthorizationPlugin;
+import org.apache.gravitino.authorization.ranger.RangerHelper;
import org.apache.gravitino.authorization.ranger.RangerMetadataObject;
import org.apache.gravitino.authorization.ranger.RangerSecurableObject;
import org.junit.jupiter.api.Assertions;
@@ -46,6 +47,38 @@ public class RangerAuthorizationPluginIT {
rangerAuthPlugin = RangerITEnv.rangerAuthHivePlugin;
}
+ @Test
+ public void testTranslateMetadataObject() {
+ MetadataObject metalake =
+ MetadataObjects.parse(String.format("metalake1"),
MetadataObject.Type.METALAKE);
+ RangerMetadataObject rangerMetalake =
rangerAuthPlugin.translateMetadataObject(metalake);
+ Assertions.assertEquals(1, rangerMetalake.names().size());
+ Assertions.assertEquals(RangerHelper.RESOURCE_ALL,
rangerMetalake.names().get(0));
+ Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA,
rangerMetalake.type());
+
+ MetadataObject catalog =
+ MetadataObjects.parse(String.format("catalog1"),
MetadataObject.Type.CATALOG);
+ RangerMetadataObject rangerCatalog =
rangerAuthPlugin.translateMetadataObject(catalog);
+ Assertions.assertEquals(1, rangerCatalog.names().size());
+ Assertions.assertEquals(RangerHelper.RESOURCE_ALL,
rangerCatalog.names().get(0));
+ Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA,
rangerCatalog.type());
+
+ MetadataObject schema =
+ MetadataObjects.parse(String.format("catalog1.schema1"),
MetadataObject.Type.SCHEMA);
+ RangerMetadataObject rangerSchema =
rangerAuthPlugin.translateMetadataObject(schema);
+ Assertions.assertEquals(1, rangerSchema.names().size());
+ Assertions.assertEquals("schema1", rangerSchema.names().get(0));
+ Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA,
rangerSchema.type());
+
+ MetadataObject table =
+ MetadataObjects.parse(String.format("catalog1.schema1.tab1"),
MetadataObject.Type.TABLE);
+ RangerMetadataObject rangerTable =
rangerAuthPlugin.translateMetadataObject(table);
+ Assertions.assertEquals(2, rangerTable.names().size());
+ Assertions.assertEquals("schema1", rangerTable.names().get(0));
+ Assertions.assertEquals("tab1", rangerTable.names().get(1));
+ Assertions.assertEquals(RangerMetadataObject.Type.TABLE,
rangerTable.type());
+ }
+
@Test
public void testTranslatePrivilege() {
SecurableObject createSchemaInMetalake =
@@ -56,7 +89,7 @@ public class RangerAuthorizationPluginIT {
List<RangerSecurableObject> createSchemaInMetalake1 =
rangerAuthPlugin.translatePrivilege(createSchemaInMetalake);
Assertions.assertEquals(1, createSchemaInMetalake1.size());
- Assertions.assertEquals("*", createSchemaInMetalake1.get(0).fullName());
+ Assertions.assertEquals(RangerHelper.RESOURCE_ALL,
createSchemaInMetalake1.get(0).fullName());
Assertions.assertEquals(
RangerMetadataObject.Type.SCHEMA,
createSchemaInMetalake1.get(0).type());
@@ -68,7 +101,7 @@ public class RangerAuthorizationPluginIT {
List<RangerSecurableObject> createSchemaInCatalog1 =
rangerAuthPlugin.translatePrivilege(createSchemaInCatalog);
Assertions.assertEquals(1, createSchemaInCatalog1.size());
- Assertions.assertEquals("*", createSchemaInCatalog1.get(0).fullName());
+ Assertions.assertEquals(RangerHelper.RESOURCE_ALL,
createSchemaInCatalog1.get(0).fullName());
Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA,
createSchemaInCatalog1.get(0).type());
for (Privilege privilege :
@@ -136,7 +169,7 @@ public class RangerAuthorizationPluginIT {
MetadataObject metalake = MetadataObjects.parse("metalake_or_catalog",
type);
List<RangerSecurableObject> metalakeOwner =
rangerAuthPlugin.translateOwner(metalake);
Assertions.assertEquals(3, metalakeOwner.size());
- Assertions.assertEquals("*", metalakeOwner.get(0).fullName());
+ Assertions.assertEquals(RangerHelper.RESOURCE_ALL,
metalakeOwner.get(0).fullName());
Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA,
metalakeOwner.get(0).type());
Assertions.assertEquals("*.*", metalakeOwner.get(1).fullName());
Assertions.assertEquals(RangerMetadataObject.Type.TABLE,
metalakeOwner.get(1).type());
diff --git
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java
index 91d58bd18..565acb82f 100644
---
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java
+++
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java
@@ -201,7 +201,6 @@ public class RangerHiveE2EIT extends BaseIT {
@AfterAll
public void stop() {
- RangerITEnv.cleanup();
if (client != null) {
Arrays.stream(catalog.asSchemas().listSchemas())
.filter(schema -> !schema.equals("default"))
@@ -222,8 +221,8 @@ public class RangerHiveE2EIT extends BaseIT {
} catch (Exception e) {
LOG.error("Failed to close CloseableGroup", e);
}
-
client = null;
+ RangerITEnv.cleanup();
}
@Test
diff --git
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java
index 85aa2f5b2..00a231e80 100644
---
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java
+++
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java
@@ -19,6 +19,7 @@
package org.apache.gravitino.authorization.ranger.integration.test;
import static
org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv.currentFunName;
+import static
org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv.rangerClient;
import static
org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv.verifyRoleInRanger;
import com.google.common.collect.ImmutableList;
@@ -34,6 +35,7 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.authorization.MetadataObjectChange;
import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Privilege;
import org.apache.gravitino.authorization.Privileges;
@@ -87,26 +89,7 @@ public class RangerHiveIT {
@AfterEach
public void clean() {
- // Clean up the test Ranger policy
- Role mockCatalogRole = mockCatalogRole(currentFunName());
- mockCatalogRole.securableObjects().stream()
- .forEach(
- securableObject -> {
- rangerAuthHivePlugin.translatePrivilege(securableObject).stream()
- .forEach(
- rangerSecurableObject -> {
- deleteHivePolicy(rangerSecurableObject);
- });
- });
- mockCatalogRole.securableObjects().stream()
- .forEach(
- securableObject -> {
- rangerAuthHivePlugin.translateOwner(securableObject).stream()
- .forEach(
- rangerSecurableObject -> {
- deleteHivePolicy(rangerSecurableObject);
- });
- });
+ RangerITEnv.cleanAllPolicy(RangerITEnv.RANGER_HIVE_REPO_NAME);
}
/**
@@ -613,6 +596,326 @@ public class RangerHiveIT {
assertFindManagedPolicy(mockCatalogRole, false);
}
+ @Test
+ public void testMetadataObjectChangeRenameMetalake() {
+ String currentFunName = currentFunName();
+ MetadataObject oldMetadataObject =
+ MetadataObjects.parse(
+ String.format("metalake-%s", currentFunName),
MetadataObject.Type.METALAKE);
+ SecurableObject oldSecurableObject1 =
+ SecurableObjects.parse(
+ oldMetadataObject.fullName(),
+ oldMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(oldSecurableObject1))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ MetadataObject newMetadataObject =
+ MetadataObjects.parse(
+ String.format("metalake-new-%s", currentFunName),
oldMetadataObject.type());
+ Assertions.assertTrue(
+ rangerAuthHivePlugin.onMetadataUpdated(
+ MetadataObjectChange.rename(oldMetadataObject,
newMetadataObject)));
+ SecurableObject newSecurableObject1 =
+ SecurableObjects.parse(
+ newMetadataObject.fullName(),
+ newMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity newRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(newSecurableObject1))
+ .build();
+ assertFindManagedPolicy(newRole, true);
+ }
+
+ @Test
+ public void testMetadataObjectChangeRenameCatalog() {
+ String currentFunName = currentFunName();
+ MetadataObject oldMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog-%s", currentFunName),
MetadataObject.Type.CATALOG);
+ SecurableObject oldSecurableObject1 =
+ SecurableObjects.parse(
+ oldMetadataObject.fullName(),
+ oldMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(oldSecurableObject1))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ MetadataObject newMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog-new-%s", currentFunName),
oldMetadataObject.type());
+ Assertions.assertTrue(
+ rangerAuthHivePlugin.onMetadataUpdated(
+ MetadataObjectChange.rename(oldMetadataObject,
newMetadataObject)));
+ SecurableObject newSecurableObject1 =
+ SecurableObjects.parse(
+ newMetadataObject.fullName(),
+ newMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity newRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(newSecurableObject1))
+ .build();
+ assertFindManagedPolicy(newRole, true);
+ }
+
+ @Test
+ public void testMetadataObjectChangeRenameSchema() {
+ String currentFunName = currentFunName();
+ MetadataObject oldMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog.old-%s", currentFunName),
MetadataObject.Type.SCHEMA);
+ SecurableObject oldSecurableObject1 =
+ SecurableObjects.parse(
+ oldMetadataObject.fullName(),
+ oldMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(oldSecurableObject1))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ MetadataObject newMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog.new-%s", currentFunName),
oldMetadataObject.type());
+ Assertions.assertTrue(
+ rangerAuthHivePlugin.onMetadataUpdated(
+ MetadataObjectChange.rename(oldMetadataObject,
newMetadataObject)));
+ assertFindManagedPolicy(role, false);
+ SecurableObject newSecurableObject1 =
+ SecurableObjects.parse(
+ newMetadataObject.fullName(),
+ newMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity newRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(newSecurableObject1))
+ .build();
+ assertFindManagedPolicy(newRole, true);
+ }
+
+ @Test
+ public void testMetadataObjectChangeRenameTable() {
+ String currentFunName = currentFunName();
+ MetadataObject oldMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog.schema1.old-%s", currentFunName),
MetadataObject.Type.TABLE);
+ SecurableObject oldSecurableObject1 =
+ SecurableObjects.parse(
+ oldMetadataObject.fullName(),
+ oldMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(oldSecurableObject1))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ MetadataObject newMetadataObject =
+ MetadataObjects.parse(
+ String.format("catalog.schema1.new-%s", currentFunName),
oldMetadataObject.type());
+ Assertions.assertTrue(
+ rangerAuthHivePlugin.onMetadataUpdated(
+ MetadataObjectChange.rename(oldMetadataObject,
newMetadataObject)));
+ assertFindManagedPolicy(role, false);
+ SecurableObject newSecurableObject1 =
+ SecurableObjects.parse(
+ newMetadataObject.fullName(),
+ newMetadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity newRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(newSecurableObject1))
+ .build();
+ assertFindManagedPolicy(newRole, true);
+ }
+
+ @Test
+ public void testMetadataObjectChangeRemoveMetalake() throws
RangerServiceException {
+ metadataObjectChangeRemoveMetalakeOrCatalog(currentFunName(),
MetadataObject.Type.METALAKE);
+ }
+
+ @Test
+ public void testMetadataObjectChangeRemoveCatalog() throws
RangerServiceException {
+ metadataObjectChangeRemoveMetalakeOrCatalog(currentFunName(),
MetadataObject.Type.CATALOG);
+ }
+
+ void metadataObjectChangeRemoveMetalakeOrCatalog(String funcName,
MetadataObject.Type type)
+ throws RangerServiceException {
+ createHivePolicy(
+ Lists.newArrayList(String.format("%s*", funcName), "*"),
+ GravitinoITUtils.genRandomName(currentFunName()));
+ createHivePolicy(
+ Lists.newArrayList(String.format("%s*", funcName), "tab*"),
+ GravitinoITUtils.genRandomName(currentFunName()));
+ createHivePolicy(
+ Lists.newArrayList(String.format("%s3", funcName), "*"),
+ GravitinoITUtils.genRandomName(currentFunName()));
+ createHivePolicy(
+ Lists.newArrayList(String.format("%s3", funcName), "tab*"),
+ GravitinoITUtils.genRandomName(currentFunName()));
+ Assertions.assertEquals(
+ 4,
rangerClient.getPoliciesInService(RangerITEnv.RANGER_HIVE_REPO_NAME).size());
+
+ String currentFunName = currentFunName();
+ MetadataObject metadataObject =
+ MetadataObjects.parse(String.format("metalake-%s", currentFunName),
type);
+ SecurableObject oldSecurableObject1 =
+ SecurableObjects.parse(
+ metadataObject.fullName(),
+ metadataObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(oldSecurableObject1))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ Assertions.assertTrue(
+
rangerAuthHivePlugin.onMetadataUpdated(MetadataObjectChange.remove(metadataObject)));
+ assertFindManagedPolicy(role, false);
+
+ Assertions.assertEquals(
+ 0,
rangerClient.getPoliciesInService(RangerITEnv.RANGER_HIVE_REPO_NAME).size());
+ }
+
+ @Test
+ public void testMetadataObjectChangeRemoveSchema() throws
RangerServiceException {
+ String currentFunName = currentFunName();
+ MetadataObject schemaObject =
+ MetadataObjects.parse(
+ String.format("catalog.old-%s", currentFunName),
MetadataObject.Type.SCHEMA);
+ SecurableObject schemaSecurableObject =
+ SecurableObjects.parse(
+ schemaObject.fullName(),
+ schemaObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ MetadataObject tableObject =
+ MetadataObjects.parse(
+ String.format("catalog.old-%s.tab1", currentFunName),
MetadataObject.Type.TABLE);
+ SecurableObject tableSecurableObject =
+ SecurableObjects.parse(
+ tableObject.fullName(),
+ tableObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(schemaSecurableObject,
tableSecurableObject))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+ Assertions.assertEquals(
+ 4,
rangerClient.getPoliciesInService(RangerITEnv.RANGER_HIVE_REPO_NAME).size());
+
+ Assertions.assertTrue(
+
rangerAuthHivePlugin.onMetadataUpdated(MetadataObjectChange.remove(schemaObject)));
+ RoleEntity roleVerify =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(schemaSecurableObject))
+ .build();
+ assertFindManagedPolicy(roleVerify, false);
+ Assertions.assertEquals(
+ 2,
rangerClient.getPoliciesInService(RangerITEnv.RANGER_HIVE_REPO_NAME).size());
+ }
+
+ @Test
+ public void testMetadataObjectChangeRemoveTable() throws
RangerServiceException {
+ String currentFunName = currentFunName();
+ MetadataObject schemaObject =
+ MetadataObjects.parse(
+ String.format("catalog.old-%s", currentFunName),
MetadataObject.Type.SCHEMA);
+ SecurableObject securableObjectSchema =
+ SecurableObjects.parse(
+ schemaObject.fullName(),
+ schemaObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ MetadataObject tableObject =
+ MetadataObjects.parse(
+ String.format("catalog.old-%s.tab1", currentFunName),
MetadataObject.Type.TABLE);
+ SecurableObject securableObjectTab =
+ SecurableObjects.parse(
+ tableObject.fullName(),
+ tableObject.type(),
+ Lists.newArrayList(Privileges.SelectTable.allow()));
+ RoleEntity role =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(securableObjectSchema,
securableObjectTab))
+ .build();
+ Assertions.assertTrue(rangerAuthHivePlugin.onRoleCreated(role));
+ assertFindManagedPolicy(role, true);
+
+ Assertions.assertTrue(
+
rangerAuthHivePlugin.onMetadataUpdated(MetadataObjectChange.remove(tableObject)));
+ RoleEntity verifyScheamRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(securableObjectSchema))
+ .build();
+ RoleEntity verifyTableRole =
+ RoleEntity.builder()
+ .withId(1L)
+ .withName(currentFunName)
+ .withAuditInfo(auditInfo)
+ .withSecurableObjects(Lists.newArrayList(securableObjectTab))
+ .build();
+ assertFindManagedPolicy(verifyScheamRole, true);
+ assertFindManagedPolicy(verifyTableRole, false);
+ Assertions.assertEquals(
+ 2,
rangerClient.getPoliciesInService(RangerITEnv.RANGER_HIVE_REPO_NAME).size());
+ }
+
+ @Test
public void testRoleChangeCombinedOperation() {
MetadataObject oldMetadataObject =
MetadataObjects.parse(
diff --git
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java
index 653d17202..be653bd3d 100644
---
a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java
+++
b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java
@@ -18,6 +18,7 @@
*/
package org.apache.gravitino.authorization.ranger.integration.test;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.Arrays;
@@ -117,24 +118,17 @@ public class RangerITEnv {
createRangerHdfsRepository("", true);
createRangerHiveRepository("", true);
allowAnyoneAccessHDFS();
- allowAnyoneAccessInformationSchema();
initRangerService = true;
}
}
}
public static void cleanup() {
- try {
- if (rangerClient != null) {
- if (rangerClient.getService(RANGER_TRINO_REPO_NAME) != null) {
- rangerClient.deleteService(RANGER_TRINO_REPO_NAME);
- }
- if (rangerClient.getService(RANGER_HIVE_REPO_NAME) != null) {
- rangerClient.deleteService(RANGER_HIVE_REPO_NAME);
- }
+ if (rangerClient != null) {
+ // Clean up the test Ranger policy
+ for (String repoName : ImmutableList.of(RANGER_HIVE_REPO_NAME,
RANGER_HDFS_REPO_NAME)) {
+ cleanAllPolicy(repoName);
}
- } catch (RangerServiceException e) {
- // ignore
}
}
@@ -598,11 +592,17 @@ public class RangerITEnv {
/** Clean all policy in the Ranger */
protected static void cleanAllPolicy(String serviceName) {
try {
- List<RangerPolicy> policies =
- rangerClient.findPolicies(ImmutableMap.of(SearchFilter.SERVICE_NAME,
serviceName));
- for (RangerPolicy policy : policies) {
- rangerClient.deletePolicy(policy.getId());
- }
+ List<RangerPolicy> policies =
rangerClient.getPoliciesInService(serviceName);
+ policies.stream()
+ .forEach(
+ policy -> {
+ try {
+ rangerClient.deletePolicy(policy.getId());
+ } catch (RangerServiceException e) {
+ LOG.error("Failed to rename the policy {}!", policy);
+ throw new RuntimeException(e);
+ }
+ });
} catch (RangerServiceException e) {
throw new RuntimeException(e);
}
diff --git
a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
index 7c9559782..8ac75a649 100644
---
a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
+++
b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
@@ -26,4 +26,7 @@ import java.io.Closeable;
* permission system, the implementation method of these function interface
must be idempotent.
*/
public interface AuthorizationPlugin
- extends UserGroupAuthorizationPlugin, RoleAuthorizationPlugin, Closeable {}
+ extends UserGroupAuthorizationPlugin,
+ RoleAuthorizationPlugin,
+ MetadataAuthorizationPlugin,
+ Closeable {}
diff --git
a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
b/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java
similarity index 56%
copy from
core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
copy to
core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java
index 7c9559782..f228d98c7 100644
---
a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java
+++
b/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java
@@ -18,12 +18,20 @@
*/
package org.apache.gravitino.connector.authorization;
-import java.io.Closeable;
+import org.apache.gravitino.authorization.MetadataObjectChange;
/**
- * Authorization operations plugin interfaces. <br>
- * Notice: Because each interface function needs to perform multiple steps in
the underlying
- * permission system, the implementation method of these function interface
must be idempotent.
+ * Interface for authorization User and Group plugin operation of the
underlying access control
+ * system.
*/
-public interface AuthorizationPlugin
- extends UserGroupAuthorizationPlugin, RoleAuthorizationPlugin, Closeable {}
+interface MetadataAuthorizationPlugin {
+ /**
+ * After updating a metadata object in Gravitino, this method is called to
update the role in the
+ * underlying system. <br>
+ *
+ * @param changes metadata object changes apply to the role.
+ * @return True if the update operation is successful; False if the update
operation fails.
+ * @throws RuntimeException If update role encounters storage issues.
+ */
+ Boolean onMetadataUpdated(MetadataObjectChange... changes) throws
RuntimeException;
+}
diff --git
a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java
b/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java
index e28dffc32..e078eda41 100644
---
a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java
+++
b/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.List;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.MetadataObjectChange;
import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.RoleChange;
@@ -110,4 +111,9 @@ public class TestMySQLAuthorizationPlugin implements
AuthorizationPlugin {
@Override
public void close() throws IOException {}
+
+ @Override
+ public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws
RuntimeException {
+ return null;
+ }
}
diff --git
a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java
b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java
index 1ed1ab9dc..8a68f825d 100644
---
a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java
+++
b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.List;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.MetadataObjectChange;
import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.RoleChange;
@@ -110,4 +111,9 @@ public class TestRangerAuthorizationPlugin implements
AuthorizationPlugin {
@Override
public void close() throws IOException {}
+
+ @Override
+ public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws
RuntimeException {
+ return null;
+ }
}