This is an automated email from the ASF dual-hosted git repository. liuxun 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 bea393441 [#5196] improve(auth-ranger): Refactor RangerSecurableObject class (#5222) bea393441 is described below commit bea3934418cb15dbd5377e9ea9be340e7e38ebea Author: Xun <x...@datastrato.com> AuthorDate: Wed Oct 23 22:18:43 2024 +0800 [#5196] improve(auth-ranger): Refactor RangerSecurableObject class (#5222) ### What changes were proposed in this pull request? 1. Add `RangerMetadataObject` class. ### Why are the changes needed? Currently, RangerSecurableObject extends MetadataObject, but Ranger managers meta types different with Gravitino, for example, Ranger doesn't have `METALAKE`, `ROLE`, So we need to Refactor RangerSecurableObject class. Fix: #5196 ### Does this PR introduce _any_ user-facing change? N/A ### How was this patch tested? CI Passed. --- .../java/org/apache/gravitino/MetadataObjects.java | 5 +- .../ranger/RangerAuthorizationHivePlugin.java | 118 ++++++++++++------- .../ranger/RangerAuthorizationPlugin.java | 17 ++- .../authorization/ranger/RangerHelper.java | 26 ++--- .../authorization/ranger/RangerMetadataObject.java | 110 ++++++++++++++++++ ...leObject.java => RangerMetadataObjectRule.java} | 24 +--- .../ranger/RangerMetadataObjects.java | 126 +++++++++++++++++++++ .../ranger/RangerSecurableObject.java | 3 +- .../ranger/RangerSecurableObjects.java | 21 ++-- .../test/RangerAuthorizationPluginIT.java} | 47 ++++---- .../ranger/integration/test/RangerHiveIT.java | 66 +++++------ build.gradle.kts | 2 +- 12 files changed, 408 insertions(+), 157 deletions(-) diff --git a/api/src/main/java/org/apache/gravitino/MetadataObjects.java b/api/src/main/java/org/apache/gravitino/MetadataObjects.java index a13036497..49fe60187 100644 --- a/api/src/main/java/org/apache/gravitino/MetadataObjects.java +++ b/api/src/main/java/org/apache/gravitino/MetadataObjects.java @@ -49,7 +49,8 @@ public class MetadataObjects { Preconditions.checkArgument(name != null, "Cannot create a metadata object with null name"); Preconditions.checkArgument(type != null, "Cannot create a metadata object with no type"); - return new MetadataObjectImpl(parent, name, type); + String fullName = parent == null ? name : DOT_JOINER.join(parent, name); + return parse(fullName, type); } /** @@ -159,7 +160,7 @@ public class MetadataObjects { * @param names The names of the metadata object * @return The parent full name if it exists, otherwise null */ - public static String getParentFullName(List<String> names) { + private static String getParentFullName(List<String> names) { if (names.size() <= 1) { return null; } 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 838385c8a..83031b764 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 @@ -60,6 +60,35 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { return instance; } + /** Validate different Ranger metadata object */ + @Override + public void validateRangerMetadataObject(List<String> names, RangerMetadataObject.Type type) + throws IllegalArgumentException { + Preconditions.checkArgument( + names != null && !names.isEmpty(), "Cannot create a Ranger metadata object with no names"); + Preconditions.checkArgument( + names.size() <= 3, + "Cannot create a Ranger metadata object with the name length which is greater than 3"); + Preconditions.checkArgument( + type != null, "Cannot create a Ranger metadata object with no type"); + + Preconditions.checkArgument( + names.size() != 1 || type == RangerMetadataObject.Type.SCHEMA, + "If the length of names is 1, it must be the SCHEMA type"); + + Preconditions.checkArgument( + names.size() != 2 || type == RangerMetadataObject.Type.TABLE, + "If the length of names is 2, it must be the TABLE type"); + + Preconditions.checkArgument( + names.size() != 3 || type == RangerMetadataObject.Type.COLUMN, + "If the length of names is 3, it must be COLUMN"); + + for (String name : names) { + RangerMetadataObjects.checkName(name); + } + } + @Override /** Set the default mapping Gravitino privilege name to the Ranger rule */ public Map<Privilege.Name, Set<RangerPrivilege>> privilegesMappingRule() { @@ -110,78 +139,79 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { } /** Translate the Gravitino securable object to the Ranger owner securable object. */ - public List<RangerSecurableObject> translateOwner(MetadataObject metadataObject) { + public List<RangerSecurableObject> translateOwner(MetadataObject gravitinoMetadataObject) { List<RangerSecurableObject> rangerSecurableObjects = new ArrayList<>(); - switch (metadataObject.type()) { + switch (gravitinoMetadataObject.type()) { case METALAKE: case CATALOG: // Add `*` for the SCHEMA permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(RangerHelper.RESOURCE_ALL), - MetadataObject.Type.SCHEMA, + RangerMetadataObject.Type.SCHEMA, ownerMappingRule())); // Add `*.*` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.TABLE, + RangerMetadataObject.Type.TABLE, ownerMappingRule())); // Add `*.*.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, ownerMappingRule())); break; case SCHEMA: // Add `{schema}` for the SCHEMA permission rangerSecurableObjects.add( - RangerSecurableObjects.of( - ImmutableList.of(metadataObject.name() /*Schema name*/), - MetadataObject.Type.SCHEMA, + generateRangerSecurableObject( + ImmutableList.of(gravitinoMetadataObject.name() /*Schema name*/), + RangerMetadataObject.Type.SCHEMA, ownerMappingRule())); // Add `{schema}.*` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( - ImmutableList.of(metadataObject.name() /*Schema name*/, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.TABLE, + generateRangerSecurableObject( + ImmutableList.of( + gravitinoMetadataObject.name() /*Schema name*/, RangerHelper.RESOURCE_ALL), + RangerMetadataObject.Type.TABLE, ownerMappingRule())); // Add `{schema}.*.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( - metadataObject.name() /*Schema name*/, + gravitinoMetadataObject.name() /*Schema name*/, RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, ownerMappingRule())); break; case TABLE: // Add `{schema}.{table}` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( - convertToRangerMetadataObject(metadataObject), - MetadataObject.Type.TABLE, + generateRangerSecurableObject( + convertToRangerMetadataObject(gravitinoMetadataObject), + RangerMetadataObject.Type.TABLE, ownerMappingRule())); // Add `{schema}.{table}.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( Stream.concat( - convertToRangerMetadataObject(metadataObject).stream(), + convertToRangerMetadataObject(gravitinoMetadataObject).stream(), Stream.of(RangerHelper.RESOURCE_ALL)) .collect(Collectors.toList()), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, ownerMappingRule())); break; default: throw new AuthorizationPluginException( "The owner privilege is not supported for the securable object: %s", - metadataObject.type()); + gravitinoMetadataObject.type()); } return rangerSecurableObjects; @@ -214,9 +244,9 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { case CATALOG: // Add Ranger privilege(`SELECT`) to SCHEMA(`*`) rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(RangerHelper.RESOURCE_ALL), - MetadataObject.Type.SCHEMA, + RangerMetadataObject.Type.SCHEMA, rangerPrivileges)); break; default: @@ -231,9 +261,9 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { case CATALOG: // Add Ranger privilege(`CREATE`) to SCHEMA(`*`) rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(RangerHelper.RESOURCE_ALL), - MetadataObject.Type.SCHEMA, + RangerMetadataObject.Type.SCHEMA, rangerPrivileges)); break; default: @@ -248,17 +278,17 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { case CATALOG: // Add Ranger privilege(`SELECT`) to SCHEMA(`*`) rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(RangerHelper.RESOURCE_ALL), - MetadataObject.Type.SCHEMA, + RangerMetadataObject.Type.SCHEMA, rangerPrivileges)); break; case SCHEMA: // Add Ranger privilege(`SELECT`) to SCHEMA(`{schema}`) rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of(securableObject.name() /*Schema name*/), - MetadataObject.Type.SCHEMA, + RangerMetadataObject.Type.SCHEMA, rangerPrivileges)); break; default: @@ -275,38 +305,38 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { case CATALOG: // Add `*.*` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.TABLE, + RangerMetadataObject.Type.TABLE, rangerPrivileges)); // Add `*.*.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, rangerPrivileges)); break; case SCHEMA: // Add `{schema}.*` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( securableObject.name() /*Schema name*/, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.TABLE, + RangerMetadataObject.Type.TABLE, rangerPrivileges)); // Add `{schema}.*.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( ImmutableList.of( securableObject.name() /*Schema name*/, RangerHelper.RESOURCE_ALL, RangerHelper.RESOURCE_ALL), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, rangerPrivileges)); break; case TABLE: @@ -317,18 +347,18 @@ public class RangerAuthorizationHivePlugin extends RangerAuthorizationPlugin { } else { // Add `{schema}.{table}` for the TABLE permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( convertToRangerMetadataObject(securableObject), - MetadataObject.Type.TABLE, + RangerMetadataObject.Type.TABLE, rangerPrivileges)); // Add `{schema}.{table}.*` for the COLUMN permission rangerSecurableObjects.add( - RangerSecurableObjects.of( + generateRangerSecurableObject( Stream.concat( convertToRangerMetadataObject(securableObject).stream(), Stream.of(RangerHelper.RESOURCE_ALL)) .collect(Collectors.toList()), - MetadataObject.Type.COLUMN, + RangerMetadataObject.Type.COLUMN, rangerPrivileges)); } break; 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 b188b55dd..e0da6b904 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 @@ -67,7 +67,7 @@ import org.slf4j.LoggerFactory; * implement Gravitino Owner concept. <br> */ public abstract class RangerAuthorizationPlugin - implements AuthorizationPlugin, RangerPrivilegesMappingProvider { + implements AuthorizationPlugin, RangerPrivilegesMappingProvider, RangerMetadataObjectRule { private static final Logger LOG = LoggerFactory.getLogger(RangerAuthorizationPlugin.class); protected final String rangerServiceName; @@ -660,7 +660,20 @@ public abstract class RangerAuthorizationPlugin @Override public void close() throws IOException {} - boolean validAuthorizationOperation(List<SecurableObject> securableObjects) { + /** Generate different Ranger securable object */ + public RangerSecurableObject generateRangerSecurableObject( + List<String> names, RangerMetadataObject.Type type, Set<RangerPrivilege> privileges) { + validateRangerMetadataObject(names, type); + RangerMetadataObject metadataObject = + new RangerMetadataObjects.RangerMetadataObjectImpl( + RangerMetadataObjects.getParentFullName(names), + RangerMetadataObjects.getLastName(names), + type); + return new RangerSecurableObjects.RangerSecurableObjectImpl( + metadataObject.parent(), metadataObject.name(), metadataObject.type(), privileges); + } + + public boolean validAuthorizationOperation(List<SecurableObject> securableObjects) { return securableObjects.stream() .allMatch( securableObject -> { 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 12a99fd61..dde7b7328 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 @@ -28,10 +28,8 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; -import org.apache.gravitino.MetadataObject; import org.apache.gravitino.authorization.Owner; import org.apache.gravitino.authorization.Privilege; -import org.apache.gravitino.authorization.SecurableObjects; import org.apache.gravitino.exceptions.AuthorizationPluginException; import org.apache.ranger.RangerClient; import org.apache.ranger.RangerServiceException; @@ -192,12 +190,12 @@ public class RangerHelper { /** * Find the managed policy for the ranger securable object. * - * @param rangerSecurableObject The ranger securable object to find the managed policy. + * @param rangerMetadataObject The ranger securable object to find the managed policy. * @return The managed policy for the metadata object. */ - public RangerPolicy findManagedPolicy(RangerSecurableObject rangerSecurableObject) + public RangerPolicy findManagedPolicy(RangerMetadataObject rangerMetadataObject) throws AuthorizationPluginException { - List<String> nsMetadataObj = getMetadataObjectNames(rangerSecurableObject); + List<String> nsMetadataObj = rangerMetadataObject.names(); Map<String, String> searchFilters = new HashMap<>(); Map<String, String> preciseFilters = new HashMap<>(); @@ -395,23 +393,13 @@ public class RangerHelper { }); } - private static List<String> getMetadataObjectNames(MetadataObject metadataObject) { - List<String> nsMetadataObject = - Lists.newArrayList(SecurableObjects.DOT_SPLITTER.splitToList(metadataObject.fullName())); - if (nsMetadataObject.size() > 4) { - // The max level of the securable object is `catalog.db.table.column` - throw new RuntimeException("The length of the securable object should not be greater than 4"); - } - return nsMetadataObject; - } - - protected RangerPolicy createPolicyAddResources(MetadataObject metadataObject) { + protected RangerPolicy createPolicyAddResources(RangerMetadataObject metadataObject) { RangerPolicy policy = new RangerPolicy(); policy.setService(rangerServiceName); policy.setName(metadataObject.fullName()); policy.setPolicyLabels(Lists.newArrayList(RangerHelper.MANAGED_BY_GRAVITINO)); - List<String> nsMetadataObject = getMetadataObjectNames(metadataObject); + List<String> nsMetadataObject = metadataObject.names(); for (int i = 0; i < nsMetadataObject.size(); i++) { RangerPolicy.RangerPolicyResource policyResource = @@ -421,7 +409,7 @@ public class RangerHelper { return policy; } - protected RangerPolicy addOwnerToNewPolicy(MetadataObject metadataObject, Owner newOwner) { + protected RangerPolicy addOwnerToNewPolicy(RangerMetadataObject metadataObject, Owner newOwner) { RangerPolicy policy = createPolicyAddResources(metadataObject); ownerPrivileges.forEach( @@ -444,7 +432,7 @@ public class RangerHelper { } protected RangerPolicy addOwnerRoleToNewPolicy( - MetadataObject metadataObject, String ownerRoleName) { + RangerMetadataObject metadataObject, String ownerRoleName) { RangerPolicy policy = createPolicyAddResources(metadataObject); ownerPrivileges.forEach( diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java new file mode 100644 index 000000000..08df90d0f --- /dev/null +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java @@ -0,0 +1,110 @@ +/* + * 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.ranger; + +import java.util.List; +import javax.annotation.Nullable; +import org.apache.gravitino.MetadataObject; +import org.apache.gravitino.annotation.Unstable; + +/** + * The Ranger MetadataObject is the basic unit of the Gravitino system. It represents the Apache + * Ranger metadata object in the Apache Gravitino system. The object can be a catalog, schema, + * table, column, etc. + */ +@Unstable +public interface RangerMetadataObject { + /** + * The type of object in the Ranger system. Every type will map one kind of the entity of the + * Gravitino type system. + */ + enum Type { + /** A schema is a sub collection of the catalog. The schema can contain tables, columns, etc. */ + SCHEMA(MetadataObject.Type.SCHEMA), + /** A table is mapped the table of relational data sources like Apache Hive, MySQL, etc. */ + TABLE(MetadataObject.Type.TABLE), + /** A column is a sub-collection of the table that represents a group of same type data. */ + COLUMN(MetadataObject.Type.COLUMN); + + private final MetadataObject.Type metadataType; + + Type(MetadataObject.Type type) { + this.metadataType = type; + } + + public MetadataObject.Type getMetadataType() { + return metadataType; + } + + public static Type fromMetadataType(MetadataObject.Type metadataType) { + for (Type type : Type.values()) { + if (type.getMetadataType() == metadataType) { + return type; + } + } + throw new IllegalArgumentException( + "No matching RangerMetadataObject.Type for " + metadataType); + } + } + + /** + * The parent full name of the object. If the object doesn't have parent, this method will return + * null. + * + * @return The parent full name of the object. + */ + @Nullable + String parent(); + + /** + * The name of th object. + * + * @return The name of the object. + */ + String name(); + + /** + * The all name list of th object. + * + * @return The name list of the object. + */ + List<String> names(); + + /** + * The full name of th object. Full name will be separated by "." to represent a string identifier + * of the object, like catalog, catalog.table, etc. + * + * @return The name of the object. + */ + default String fullName() { + if (parent() == null) { + return name(); + } else { + return parent() + "." + name(); + } + } + + /** + * The type of the object. + * + * @return The type of the object. + */ + Type type(); +} diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjectRule.java similarity index 52% copy from authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java copy to authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjectRule.java index 3cdc4e514..a8de00518 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjectRule.java @@ -19,24 +19,10 @@ package org.apache.gravitino.authorization.ranger; import java.util.List; -import org.apache.gravitino.MetadataObject; -import org.apache.gravitino.annotation.Unstable; -/** - * The Ranger securable object is the entity which access can be granted. Unless allowed by a grant, - * access is denied. <br> - * You can use the helper class `RangerSecurableObjects` to create the Ranger securable object which - * you need. <br> - * There is a clear difference between Ranger's Securable Object and Gravitino's Securable Object, - * Ranger's Securable Object does not have the concept of `METALAKE`, so it needs to be defined - * specifically. - */ -@Unstable -public interface RangerSecurableObject extends MetadataObject { - /** - * The privileges of the Ranger securable object. - * - * @return The privileges of the securable object. - */ - List<RangerPrivilege> privileges(); +/** Different underlying datasource have different Ranger metadata object rules */ +interface RangerMetadataObjectRule { + /** Validate different underlying datasource Ranger metadata object */ + void validateRangerMetadataObject(List<String> names, RangerMetadataObject.Type type) + throws IllegalArgumentException; } 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 new file mode 100644 index 000000000..de2002df1 --- /dev/null +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObjects.java @@ -0,0 +1,126 @@ +/* + * 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.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('.'); + + private static final Joiner DOT_JOINER = Joiner.on('.'); + + private RangerMetadataObjects() {} + + /** + * Get the parent full name of the given full name. + * + * @param names The names of the metadata object + * @return The parent full name if it exists, otherwise null + */ + public static String getParentFullName(List<String> names) { + if (names.size() <= 1) { + return null; + } + + return DOT_JOINER.join(names.subList(0, names.size() - 1)); + } + + static String getLastName(List<String> names) { + Preconditions.checkArgument(names.size() > 0, "Cannot get the last name of an empty list"); + return names.get(names.size() - 1); + } + + static void checkName(String name) { + Preconditions.checkArgument(name != null, "Cannot create a metadata object with null name"); + } + + /** The implementation of the {@link MetadataObject}. */ + public static class RangerMetadataObjectImpl implements RangerMetadataObject { + private final String name; + + private final String parent; + + private final RangerMetadataObject.Type type; + + /** + * Create the metadata object with the given name, parent and type. + * + * @param parent The parent of the metadata object + * @param name The name of the metadata object + * @param type The type of the metadata object + */ + public RangerMetadataObjectImpl(String parent, String name, RangerMetadataObject.Type type) { + this.parent = parent; + this.name = name; + this.type = type; + } + + @Override + public String name() { + return name; + } + + @Override + public List<String> names() { + return Lists.newArrayList(DOT_SPLITTER.splitToList(fullName())); + } + + @Override + public String parent() { + return parent; + } + + @Override + public Type type() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof RangerMetadataObjectImpl)) { + return false; + } + + RangerMetadataObjectImpl that = (RangerMetadataObjectImpl) o; + return java.util.Objects.equals(name, that.name) + && java.util.Objects.equals(parent, that.parent) + && type == that.type; + } + + @Override + public int hashCode() { + return java.util.Objects.hash(name, parent, type); + } + + @Override + public String toString() { + return "MetadataObject: [fullName=" + fullName() + "], [type=" + type + "]"; + } + } +} diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java index 3cdc4e514..da3311a17 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java @@ -19,7 +19,6 @@ package org.apache.gravitino.authorization.ranger; import java.util.List; -import org.apache.gravitino.MetadataObject; import org.apache.gravitino.annotation.Unstable; /** @@ -32,7 +31,7 @@ import org.apache.gravitino.annotation.Unstable; * specifically. */ @Unstable -public interface RangerSecurableObject extends MetadataObject { +public interface RangerSecurableObject extends RangerMetadataObject { /** * The privileges of the Ranger securable object. * diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObjects.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObjects.java index 6405e3e4c..999f78684 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObjects.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObjects.java @@ -22,23 +22,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import java.util.List; import java.util.Set; -import org.apache.gravitino.MetadataObject; -import org.apache.gravitino.MetadataObjects; -import org.apache.gravitino.MetadataObjects.MetadataObjectImpl; +import org.apache.gravitino.authorization.ranger.RangerMetadataObjects.RangerMetadataObjectImpl; /** The helper class for {@link RangerSecurableObject}. */ public class RangerSecurableObjects { - public static RangerSecurableObject of( - List<String> names, MetadataObject.Type type, Set<RangerPrivilege> privileges) { - MetadataObject metadataObject = - MetadataObjects.of( - MetadataObjects.getParentFullName(names), names.get(names.size() - 1), type); - return new RangerSecurableObjectImpl( - metadataObject.parent(), metadataObject.name(), type, privileges); - } - - private static class RangerSecurableObjectImpl extends MetadataObjectImpl + public static class RangerSecurableObjectImpl extends RangerMetadataObjectImpl implements RangerSecurableObject { + private final List<RangerPrivilege> privileges; /** @@ -49,7 +39,10 @@ public class RangerSecurableObjects { * @param type The type of the metadata object */ public RangerSecurableObjectImpl( - String parent, String name, Type type, Set<RangerPrivilege> privileges) { + String parent, + String name, + RangerMetadataObject.Type type, + Set<RangerPrivilege> privileges) { super(parent, name, type); this.privileges = ImmutableList.copyOf(Sets.newHashSet(privileges)); } diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/TestRangerAuthorizationPlugin.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java similarity index 93% rename from authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/TestRangerAuthorizationPlugin.java rename to authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java index d4f314dd7..32eb58d18 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/TestRangerAuthorizationPlugin.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.authorization.ranger; +package org.apache.gravitino.authorization.ranger.integration.test; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -28,12 +28,16 @@ import org.apache.gravitino.authorization.Privilege; import org.apache.gravitino.authorization.Privileges; import org.apache.gravitino.authorization.SecurableObject; import org.apache.gravitino.authorization.SecurableObjects; -import org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv; +import org.apache.gravitino.authorization.ranger.RangerAuthorizationPlugin; +import org.apache.gravitino.authorization.ranger.RangerMetadataObject; +import org.apache.gravitino.authorization.ranger.RangerSecurableObject; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -public class TestRangerAuthorizationPlugin { +@Tag("gravitino-docker-test") +public class RangerAuthorizationPluginIT { private static RangerAuthorizationPlugin rangerAuthPlugin; @BeforeAll @@ -53,7 +57,8 @@ public class TestRangerAuthorizationPlugin { rangerAuthPlugin.translatePrivilege(createSchemaInMetalake); Assertions.assertEquals(1, createSchemaInMetalake1.size()); Assertions.assertEquals("*", createSchemaInMetalake1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.SCHEMA, createSchemaInMetalake1.get(0).type()); + Assertions.assertEquals( + RangerMetadataObject.Type.SCHEMA, createSchemaInMetalake1.get(0).type()); SecurableObject createSchemaInCatalog = SecurableObjects.parse( @@ -64,7 +69,7 @@ public class TestRangerAuthorizationPlugin { rangerAuthPlugin.translatePrivilege(createSchemaInCatalog); Assertions.assertEquals(1, createSchemaInCatalog1.size()); Assertions.assertEquals("*", createSchemaInCatalog1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.SCHEMA, createSchemaInCatalog1.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA, createSchemaInCatalog1.get(0).type()); for (Privilege privilege : ImmutableList.of( @@ -79,9 +84,9 @@ public class TestRangerAuthorizationPlugin { List<RangerSecurableObject> metalake1 = rangerAuthPlugin.translatePrivilege(metalake); Assertions.assertEquals(2, metalake1.size()); Assertions.assertEquals("*.*", metalake1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, metalake1.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, metalake1.get(0).type()); Assertions.assertEquals("*.*.*", metalake1.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, metalake1.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, metalake1.get(1).type()); SecurableObject catalog = SecurableObjects.parse( @@ -91,9 +96,9 @@ public class TestRangerAuthorizationPlugin { List<RangerSecurableObject> catalog1 = rangerAuthPlugin.translatePrivilege(catalog); Assertions.assertEquals(2, catalog1.size()); Assertions.assertEquals("*.*", catalog1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, catalog1.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, catalog1.get(0).type()); Assertions.assertEquals("*.*.*", catalog1.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, catalog1.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, catalog1.get(1).type()); SecurableObject schema = SecurableObjects.parse( @@ -103,9 +108,9 @@ public class TestRangerAuthorizationPlugin { List<RangerSecurableObject> schema1 = rangerAuthPlugin.translatePrivilege(schema); Assertions.assertEquals(2, schema1.size()); Assertions.assertEquals("schema1.*", schema1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, schema1.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, schema1.get(0).type()); Assertions.assertEquals("schema1.*.*", schema1.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, schema1.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, schema1.get(1).type()); if (!privilege.equals(Privileges.CreateTable.allow())) { // `CREATE_TABLE` not support securable object for table, So ignore check for table. @@ -117,9 +122,9 @@ public class TestRangerAuthorizationPlugin { List<RangerSecurableObject> table1 = rangerAuthPlugin.translatePrivilege(table); Assertions.assertEquals(2, table1.size()); Assertions.assertEquals("schema1.table1", table1.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, table1.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, table1.get(0).type()); Assertions.assertEquals("schema1.table1.*", table1.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, table1.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, table1.get(1).type()); } } } @@ -132,31 +137,31 @@ public class TestRangerAuthorizationPlugin { List<RangerSecurableObject> metalakeOwner = rangerAuthPlugin.translateOwner(metalake); Assertions.assertEquals(3, metalakeOwner.size()); Assertions.assertEquals("*", metalakeOwner.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.SCHEMA, metalakeOwner.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA, metalakeOwner.get(0).type()); Assertions.assertEquals("*.*", metalakeOwner.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, metalakeOwner.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, metalakeOwner.get(1).type()); Assertions.assertEquals("*.*.*", metalakeOwner.get(2).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, metalakeOwner.get(2).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, metalakeOwner.get(2).type()); } MetadataObject schema = MetadataObjects.parse("catalog1.schema1", MetadataObject.Type.SCHEMA); List<RangerSecurableObject> schemaOwner = rangerAuthPlugin.translateOwner(schema); Assertions.assertEquals(3, schemaOwner.size()); Assertions.assertEquals("schema1", schemaOwner.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.SCHEMA, schemaOwner.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.SCHEMA, schemaOwner.get(0).type()); Assertions.assertEquals("schema1.*", schemaOwner.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, schemaOwner.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, schemaOwner.get(1).type()); Assertions.assertEquals("schema1.*.*", schemaOwner.get(2).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, schemaOwner.get(2).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, schemaOwner.get(2).type()); MetadataObject table = MetadataObjects.parse("catalog1.schema1.table1", MetadataObject.Type.TABLE); List<RangerSecurableObject> tableOwner = rangerAuthPlugin.translateOwner(table); Assertions.assertEquals(2, tableOwner.size()); Assertions.assertEquals("schema1.table1", tableOwner.get(0).fullName()); - Assertions.assertEquals(MetadataObject.Type.TABLE, tableOwner.get(0).type()); + Assertions.assertEquals(RangerMetadataObject.Type.TABLE, tableOwner.get(0).type()); Assertions.assertEquals("schema1.table1.*", tableOwner.get(1).fullName()); - Assertions.assertEquals(MetadataObject.Type.COLUMN, tableOwner.get(1).type()); + Assertions.assertEquals(RangerMetadataObject.Type.COLUMN, tableOwner.get(1).type()); } @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 eba00a188..c105d42fd 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 @@ -18,7 +18,6 @@ */ package org.apache.gravitino.authorization.ranger.integration.test; -import static org.apache.gravitino.authorization.SecurableObjects.DOT_SPLITTER; import static org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv.currentFunName; import static org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv.verifyRoleInRanger; @@ -43,9 +42,9 @@ 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.RangerPrivileges; import org.apache.gravitino.authorization.ranger.RangerSecurableObject; -import org.apache.gravitino.authorization.ranger.RangerSecurableObjects; import org.apache.gravitino.authorization.ranger.reference.RangerDefines; import org.apache.gravitino.integration.test.util.GravitinoITUtils; import org.apache.gravitino.meta.AuditInfo; @@ -249,9 +248,9 @@ public class RangerHiveIT { GravitinoITUtils.genRandomName(currentFunName())); // findManagedPolicy function use precise search, so return null RangerSecurableObject rangerSecurableObject = - RangerSecurableObjects.of( + rangerAuthHivePlugin.generateRangerSecurableObject( ImmutableList.of(String.format("%s3", dbName), "tab1"), - MetadataObject.Type.TABLE, + RangerMetadataObject.Type.TABLE, ImmutableSet.of( new RangerPrivileges.RangerHivePrivilegeImpl( RangerPrivileges.RangerHivePrivilege.ALL, Privilege.Condition.ALLOW))); @@ -515,7 +514,11 @@ public class RangerHiveIT { String userName = "user1"; rangerAuthHivePlugin.onOwnerSet( oldMetadataObject, null, new MockOwner(userName, Owner.Type.USER)); - verifyOwnerInRanger(oldMetadataObject, Lists.newArrayList(userName)); + rangerAuthHivePlugin.translateOwner(oldMetadataObject).stream() + .forEach( + rangerSecurableObject -> { + verifyOwnerInRanger(rangerSecurableObject, Lists.newArrayList(userName)); + }); SecurableObject oldSecurableObject = SecurableObjects.parse( @@ -552,13 +555,21 @@ public class RangerHiveIT { .withSecurableObjects(Lists.newArrayList(newSecurableObject)) .build(); verifyRoleInRanger(rangerAuthHivePlugin, verifyRole); - verifyOwnerInRanger(oldMetadataObject, Lists.newArrayList(userName)); + rangerAuthHivePlugin.translateOwner(oldMetadataObject).stream() + .forEach( + rangerSecurableObject -> { + verifyOwnerInRanger(rangerSecurableObject, Lists.newArrayList(userName)); + }); // Delete the role Assertions.assertTrue(rangerAuthHivePlugin.onRoleDeleted(verifyRole)); // Because these metaobjects have an owner, so the policy will not be deleted. assertFindManagedPolicy(role, true); - verifyOwnerInRanger(oldMetadataObject, Lists.newArrayList(userName)); + rangerAuthHivePlugin.translateOwner(oldMetadataObject).stream() + .forEach( + rangerSecurableObject -> { + verifyOwnerInRanger(rangerSecurableObject, Lists.newArrayList(userName)); + }); } @Test @@ -899,7 +910,12 @@ public class RangerHiveIT { String ownerName = "owner1"; rangerAuthHivePlugin.onOwnerSet( securableObject1, null, new MockOwner(ownerName, Owner.Type.USER)); - verifyOwnerInRanger(securableObject1, Lists.newArrayList(ownerName), null, null, null); + rangerAuthHivePlugin.translateOwner(securableObject1).stream() + .forEach( + rangerSecurableObject -> { + verifyOwnerInRanger( + rangerSecurableObject, Lists.newArrayList(ownerName), null, null, null); + }); RoleEntity role1 = RoleEntity.builder() @@ -1277,23 +1293,13 @@ public class RangerHiveIT { assertFindManagedPolicy(role3, true); } - private static String generatePolicyName(MetadataObject metadataObject) { - List<String> nsMetadataObject = - Lists.newArrayList(SecurableObjects.DOT_SPLITTER.splitToList(metadataObject.fullName())); - if (!(metadataObject instanceof RangerSecurableObject) - && metadataObject.type() != MetadataObject.Type.METALAKE) { - nsMetadataObject.remove(0); // remove `catalog` - } - return String.join(".", nsMetadataObject); - } - /** * Verify the Gravitino role in Ranger service * * <p>metadataObject: the Gravitino securable object to be verified */ private void verifyOwnerInRanger( - MetadataObject metadataObject, + RangerMetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers, List<String> includeGroups, @@ -1301,7 +1307,7 @@ public class RangerHiveIT { List<String> includeRoles, List<String> excludeRoles) { // Find policy by each metadata Object - String policyName = generatePolicyName(metadataObject); + String policyName = metadataObject.fullName(); RangerPolicy policy; try { policy = RangerITEnv.rangerClient.getPolicy(RangerITEnv.RANGER_HIVE_REPO_NAME, policyName); @@ -1315,13 +1321,7 @@ public class RangerHiveIT { Assertions.assertTrue(policy.getPolicyLabels().contains(RangerHelper.MANAGED_BY_GRAVITINO)); // verify namespace - List<String> metaObjNamespaces = - Lists.newArrayList(DOT_SPLITTER.splitToList(metadataObject.fullName())); - if (!(metadataObject instanceof RangerSecurableObject) - && metadataObject.type() != MetadataObject.Type.METALAKE) { - metaObjNamespaces.remove(0); // skip catalog - } - + List<String> metaObjNamespaces = metadataObject.names(); List<String> rolePolicies = new ArrayList<>(); for (int i = 0; i < metaObjNamespaces.size(); i++) { rolePolicies.add( @@ -1402,21 +1402,21 @@ public class RangerHiveIT { }); } - private void verifyOwnerInRanger(MetadataObject metadataObject) { + private void verifyOwnerInRanger(RangerMetadataObject metadataObject) { verifyOwnerInRanger(metadataObject, null, null, null, null, null, null); } - private void verifyOwnerInRanger(MetadataObject metadataObject, List<String> includeUsers) { + private void verifyOwnerInRanger(RangerMetadataObject metadataObject, List<String> includeUsers) { verifyOwnerInRanger(metadataObject, includeUsers, null, null, null, null, null); } private void verifyOwnerInRanger( - MetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers) { + RangerMetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers) { verifyOwnerInRanger(metadataObject, includeUsers, excludeUsers, null, null, null, null); } private void verifyOwnerInRanger( - MetadataObject metadataObject, + RangerMetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers, List<String> includeGroups) { @@ -1425,7 +1425,7 @@ public class RangerHiveIT { } private void verifyOwnerInRanger( - MetadataObject metadataObject, + RangerMetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers, List<String> includeGroups, @@ -1435,7 +1435,7 @@ public class RangerHiveIT { } private void verifyOwnerInRanger( - MetadataObject metadataObject, + RangerMetadataObject metadataObject, List<String> includeUsers, List<String> excludeUsers, List<String> includeGroups, diff --git a/build.gradle.kts b/build.gradle.kts index b954aaf10..d4eaee1e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -146,7 +146,7 @@ allprojects { "$1" ) - targetExclude("**/build/**") + targetExclude("**/build/**", "**/.pnpm/***") } kotlinGradle {