From 5d097f64ae48bc11ef5c92ab31e61d9d4d73aee3 Mon Sep 17 00:00:00 2001 From: xunliu Date: Wed, 28 Aug 2024 12:58:33 +0800 Subject: [PATCH] [#4698] feat(core): Extended Apache Ranger authorization by configuration 1 1 --- .../authorization-ranger/build.gradle.kts | 24 +- .../ranger/AuthorizationConfig.java | 101 ++++++++ .../ranger/RangerAuthorizationPlugin.java | 11 +- .../authorization/ranger/RangerHelper.java | 218 ++++++++++-------- .../authorization/ranger/RangerPrivilege.java | 81 +++++++ .../ranger/RangerPrivileges.java | 42 ++++ .../ranger/reference/RangerDefines.java | 77 ++----- .../authorization-hive.properties.template | 32 +++ .../ranger/AuthorizationConfigTest.java | 80 +++++++ .../ranger/integration/test/RangerHiveIT.java | 95 ++------ .../ranger/integration/test/RangerITEnv.java | 69 ++++-- .../authorization-hive.properties | 32 +++ integration-test-common/build.gradle.kts | 1 + .../test/container/RangerContainer.java | 6 +- 14 files changed, 611 insertions(+), 258 deletions(-) create mode 100644 authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/AuthorizationConfig.java create mode 100644 authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilege.java create mode 100644 authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java create mode 100644 authorizations/authorization-ranger/src/main/resources/authorization-defs/authorization-hive.properties.template create mode 100644 authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/AuthorizationConfigTest.java create mode 100644 authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive.properties diff --git a/authorizations/authorization-ranger/build.gradle.kts b/authorizations/authorization-ranger/build.gradle.kts index 9121a414ad0..e99f1e9040b 100644 --- a/authorizations/authorization-ranger/build.gradle.kts +++ b/authorizations/authorization-ranger/build.gradle.kts @@ -85,18 +85,36 @@ dependencies { tasks { val runtimeJars by registering(Copy::class) { - from(configurations.runtimeClasspath) + from(configurations.runtimeClasspath, "src/main/resources") into("build/libs") + rename { original -> + if (original.endsWith(".properties.template")) { + original.replace(".properties.template", ".properties") + } else { + original + } + } } val copyAuthorizationLibs by registering(Copy::class) { - dependsOn("jar", "runtimeJars") + dependsOn("jar", runtimeJars) from("build/libs") into("$rootDir/distribution/package/authorizations/ranger/libs") } + val copyAuthorizationConfig by registering(Copy::class) { + from("src/main/resources") + into("$rootDir/distribution/package/authorizations/ranger/conf") + exclude("META-INF") + fileMode = 0b111101101 + } + register("copyLibAndConfig", Copy::class) { - dependsOn(copyAuthorizationLibs) + dependsOn(copyAuthorizationLibs, copyAuthorizationConfig) + } + + jar { + dependsOn(runtimeJars) } } diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/AuthorizationConfig.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/AuthorizationConfig.java new file mode 100644 index 00000000000..08f010bc2cb --- /dev/null +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/AuthorizationConfig.java @@ -0,0 +1,101 @@ +/* + * 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.collect.Lists; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Properties; +import org.apache.commons.lang3.StringUtils; +import org.apache.gravitino.Config; +import org.apache.gravitino.config.ConfigBuilder; +import org.apache.gravitino.config.ConfigConstants; +import org.apache.gravitino.config.ConfigEntry; + +public class AuthorizationConfig extends Config { + public static final ConfigEntry> AUTHORIZATION_OWNER_PRIVILEGES = + new ConfigBuilder("gravitino.authorization.owner.privileges") + .doc("The privileges that the owner of a security object has.") + .version(ConfigConstants.VERSION_0_7_0) + .stringConf() + .toSequence() + .checkValue( + valueList -> + valueList != null && valueList.stream().allMatch(StringUtils::isNotBlank), + ConfigConstants.NOT_BLANK_ERROR_MSG) + .createWithDefault(Lists.newArrayList()); + + public static final ConfigEntry> RANGER_POLICY_RESOURCE_DEFINES = + new ConfigBuilder("gravitino.authorization.ranger.policy.resource.defines") + .doc("The resource defines that are used in Ranger policies.") + .version(ConfigConstants.VERSION_0_7_0) + .stringConf() + .toSequence() + .checkValue( + valueList -> + valueList != null && valueList.stream().allMatch(StringUtils::isNotBlank), + ConfigConstants.NOT_BLANK_ERROR_MSG) + .createWithDefault(Lists.newArrayList()); + + public static final String PRIVILEGE_MAPPING_PREFIX = + "gravitino.authorization.privilege.mapping."; + + public static AuthorizationConfig loadConfig(String provideName) { + AuthorizationConfig authorizationConfig = new AuthorizationConfig(); + boolean testEnv = System.getenv("GRAVITINO_TEST") != null; + String propertyFilePath = + String.format("authorization-defs/authorization-%s.properties", provideName); + + // Only load from resources in test environment + if (testEnv) { + URL resourceUrl = AuthorizationConfig.class.getResource(File.separator + propertyFilePath); + try { + if (resourceUrl != null) { + Properties properties = + authorizationConfig.loadPropertiesFromFile(new File(resourceUrl.getPath())); + authorizationConfig.loadFromProperties(properties); + return authorizationConfig; + } + } catch (IOException e) { + throw new IllegalArgumentException( + "Failed to load authorization config from resource " + resourceUrl, e); + } + } + + // Load from configuration directory in production environment + String confPath = + String.join( + File.separator, + System.getenv("GRAVITINO_HOME"), + "authorizations", + provideName, + "conf", + propertyFilePath); + try { + Properties properties = authorizationConfig.loadPropertiesFromFile(new File(confPath)); + authorizationConfig.loadFromProperties(properties); + } catch (IOException e) { + throw new IllegalArgumentException( + "Failed to load authorization config from file " + confPath, e); + } + return authorizationConfig; + } +} 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 75692e987b8..bf34fbbc5fa 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 @@ -20,7 +20,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; import java.io.IOException; import java.time.Instant; import java.util.Collections; @@ -87,7 +86,8 @@ public RangerAuthorizationPlugin(String catalogProvider, Map con RangerHelper.check(password != null, "Ranger password is required"); RangerHelper.check(rangerServiceName != null, "Ranger service name is required"); rangerClient = new RangerClientExtend(rangerUrl, authType, rangerAdminName, password); - rangerHelper = new RangerHelper(this, catalogProvider); + rangerHelper = + new RangerHelper(catalogProvider, rangerClient, rangerAdminName, rangerServiceName); } /** @@ -97,12 +97,11 @@ public RangerAuthorizationPlugin(String catalogProvider, Map con * @return The corresponding privilege name in the underlying permission system */ public Set translatePrivilege(Privilege.Name name) { - return rangerHelper.privilegesMapping.get(name); + return rangerHelper.translatePrivilege(name); } - @VisibleForTesting - public List getOwnerPrivileges() { - return Lists.newArrayList(rangerHelper.ownerPrivileges); + public Set getOwnerPrivileges() { + return rangerHelper.getOwnerPrivileges(); } /** 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 aad1ebe764e..45837f94b19 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 @@ -18,13 +18,12 @@ */ package org.apache.gravitino.authorization.ranger; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.errorprone.annotations.FormatMethod; import com.google.errorprone.annotations.FormatString; -import java.util.Arrays; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -56,12 +55,11 @@ public class RangerHelper { private static final Logger LOG = LoggerFactory.getLogger(RangerHelper.class); public static final String MANAGED_BY_GRAVITINO = "MANAGED_BY_GRAVITINO"; - RangerAuthorizationPlugin rangerAuthorizationPlugin; /** Mapping Gravitino privilege name to the underlying authorization system privileges. */ - protected Map> privilegesMapping = null; + protected Map> privilegesMapping = new HashMap<>(); /** The owner privileges, the owner can do anything on the metadata object */ - protected Set ownerPrivileges = null; + private Set ownerPrivileges = new HashSet<>(); /** * Because Ranger doesn't support the precise search, Ranger will return the policy meets the @@ -69,70 +67,112 @@ public class RangerHelper { * match `db1.table1`, `db1.table2`, `db*.table*`, So we need to manually precisely filter this * research results.
* policySearchKeys: The search Ranger policy condition key defines.
- * policyPreciseFilterKeys: The precise filter Ranger search results key defines
+ * policyResourceDefines: The Ranger policy resource defines.
*/ - protected List policySearchKeys = null; - - protected List policyPreciseFilterKeys = null; - - public RangerHelper(RangerAuthorizationPlugin rangerAuthorizationPlugin, String catalogProvider) { - this.rangerAuthorizationPlugin = rangerAuthorizationPlugin; - switch (catalogProvider) { - case "hive": - initPrivilegesMapping(); - initOwnerPrivileges(); - initPolicySearchKeys(); - initPreciseFilterKeys(); - break; - default: - throw new IllegalArgumentException( - "Authorization plugin unsupported catalog provider: " + catalogProvider); - } + private List policySearchKeys = new ArrayList<>(); + + private List policyResourceDefines = new ArrayList<>(); + + private final RangerClientExtend rangerClient; + private final String rangerAdminName; + private final String rangerServiceName; + private AuthorizationConfig authorizationConfig = null; + + public RangerHelper( + String catalogProvider, + RangerClientExtend rangerClient, + String rangerAdminName, + String rangerServiceName) { + this.rangerClient = rangerClient; + this.rangerAdminName = rangerAdminName; + this.rangerServiceName = rangerServiceName; + + this.authorizationConfig = AuthorizationConfig.loadConfig(catalogProvider); + initAuthorizationConfig(authorizationConfig); } - /** Initial mapping Gravitino privilege name to the underlying authorization system privileges. */ - private void initPrivilegesMapping() { - privilegesMapping = - ImmutableMap.>builder() - .put( - Privilege.Name.CREATE_SCHEMA, - ImmutableSet.of(RangerDefines.ACCESS_TYPE_HIVE_CREATE)) - .put( - Privilege.Name.CREATE_TABLE, ImmutableSet.of(RangerDefines.ACCESS_TYPE_HIVE_CREATE)) - .put( - Privilege.Name.MODIFY_TABLE, - ImmutableSet.of( - RangerDefines.ACCESS_TYPE_HIVE_UPDATE, - RangerDefines.ACCESS_TYPE_HIVE_ALTER, - RangerDefines.ACCESS_TYPE_HIVE_WRITE)) - .put( - Privilege.Name.SELECT_TABLE, - ImmutableSet.of( - RangerDefines.ACCESS_TYPE_HIVE_READ, RangerDefines.ACCESS_TYPE_HIVE_SELECT)) - .build(); + @VisibleForTesting + RangerHelper(AuthorizationConfig authorizationConfig) { + this.rangerClient = null; + this.rangerAdminName = null; + this.rangerServiceName = null; + + this.authorizationConfig = authorizationConfig; + initAuthorizationConfig(authorizationConfig); } - /** Initial Owner privileges */ - private void initOwnerPrivileges() { - ownerPrivileges = ImmutableSet.of(RangerDefines.ACCESS_TYPE_HIVE_ALL); + /** + * Initial mapping Gravitino privilege name to the underlying authorization system privileges. + *
+ * Initial Owner privileges.
+ * Initial Ranger policy search key defines.
+ * Initial precise filter key defines.
+ */ + private void initAuthorizationConfig(AuthorizationConfig authorizationConfig) { + // Initial mapping Gravitino privilege name to the underlying authorization system privileges. + try { + authorizationConfig + .getConfigsWithPrefix(AuthorizationConfig.PRIVILEGE_MAPPING_PREFIX) + .forEach( + (key, value) -> { + Privilege.Name gravitinoPrivilege = + Privilege.Name.valueOf(key.trim().toUpperCase()); + Set strRangerPrivileges = Sets.newHashSet(value.split(",")); + // Check the privilege mapping configured if support in the Ranger + RangerHelper.check( + strRangerPrivileges.size() > 0, + "The privilege mapping value should not be empty"); + Set rangerPrivileges = + strRangerPrivileges.stream() + .map(v -> RangerPrivileges.valueOf(v)) + .collect(Collectors.toSet()); + privilegesMapping.put(gravitinoPrivilege, rangerPrivileges); + }); + } catch (IllegalArgumentException e) { + throw new AuthorizationPluginException(e); + } + + // Initial Owner privileges + authorizationConfig.get(AuthorizationConfig.AUTHORIZATION_OWNER_PRIVILEGES).stream() + .map(RangerPrivileges::valueOf) + .forEach(ownerPrivileges::add); + RangerHelper.check(ownerPrivileges.size() > 0, "The owner privileges should not be empty"); + + // Initial Ranger policy search key defines + // Ranger policy search keys format: `resource:database`, `resource:table`, `resource:column` + authorizationConfig.get(AuthorizationConfig.RANGER_POLICY_RESOURCE_DEFINES).stream() + .forEach( + resource -> { + // Check the policy resource configured if support in the Ranger + RangerDefines.PolicyResource policyResource = + RangerDefines.PolicyResource.valueOf(resource.trim().toUpperCase()); + policySearchKeys.add(SearchFilter.RESOURCE_PREFIX + policyResource.toString()); + policyResourceDefines.add(policyResource.toString()); + }); + RangerHelper.check(policySearchKeys.size() > 0, "The policy search keys should not be empty"); + RangerHelper.check( + policyResourceDefines.size() > 0, "The policy resource defines should not be empty"); } - /** Initial Ranger policy search key defines */ - private void initPolicySearchKeys() { - policySearchKeys = - Arrays.asList( - RangerDefines.SEARCH_FILTER_DATABASE, - RangerDefines.SEARCH_FILTER_TABLE, - RangerDefines.SEARCH_FILTER_COLUMN); + /** + * Translate the privilege name to the corresponding privilege name in the Ranger + * + * @param name The privilege name to translate + * @return The corresponding Ranger privilege name in the underlying permission system + */ + public Set translatePrivilege(Privilege.Name name) { + return privilegesMapping.get(name).stream() + .map(RangerPrivilege::toString) + .collect(Collectors.toSet()); } - /** Initial precise filter key defines */ - private void initPreciseFilterKeys() { - policyPreciseFilterKeys = - Arrays.asList( - RangerDefines.RESOURCE_DATABASE, - RangerDefines.RESOURCE_TABLE, - RangerDefines.RESOURCE_COLUMN); + /** + * Get the owner privilege to the corresponding privilege name in the Ranger + * + * @return The corresponding Ranger privilege name in the underlying permission system + */ + public Set getOwnerPrivileges() { + return ownerPrivileges.stream().map(RangerPrivilege::toString).collect(Collectors.toSet()); } /** @@ -176,10 +216,9 @@ void addPolicyItem(RangerPolicy policy, String roleName, SecurableObject securab .forEach( gravitinoPrivilege -> { // Translate the Gravitino privilege to map Ranger privilege - rangerAuthorizationPlugin - .translatePrivilege(gravitinoPrivilege.name()) + translatePrivilege(gravitinoPrivilege.name()) .forEach( - mappedPrivilege -> { + rangerPrivilege -> { // Find the policy item that matches Gravitino privilege List matchPolicyItems = policy.getPolicyItems().stream() @@ -187,7 +226,7 @@ void addPolicyItem(RangerPolicy policy, String roleName, SecurableObject securab policyItem -> { return policyItem.getAccesses().stream() .anyMatch( - access -> access.getType().equals(mappedPrivilege)); + access -> access.getType().equals(rangerPrivilege)); }) .collect(Collectors.toList()); @@ -197,7 +236,7 @@ void addPolicyItem(RangerPolicy policy, String roleName, SecurableObject securab new RangerPolicy.RangerPolicyItem(); RangerPolicy.RangerPolicyItemAccess access = new RangerPolicy.RangerPolicyItemAccess(); - access.setType(mappedPrivilege); + access.setType(rangerPrivilege); policyItem.getAccesses().add(access); policyItem.getRoles().add(roleName); if (Privilege.Condition.ALLOW == gravitinoPrivilege.condition()) { @@ -240,10 +279,7 @@ void removePolicyItem(RangerPolicy policy, String roleName, SecurableObject secu boolean matchPrivilege = securableObject.privileges().stream() .filter(Objects::nonNull) - .flatMap( - privilege -> - rangerAuthorizationPlugin - .translatePrivilege(privilege.name()).stream()) + .flatMap(privilege -> translatePrivilege(privilege.name()).stream()) .filter(Objects::nonNull) .anyMatch( privilege -> { @@ -297,17 +333,15 @@ public RangerPolicy findManagedPolicy(MetadataObject metadataObject) Map searchFilters = new HashMap<>(); Map preciseFilters = new HashMap<>(); - searchFilters.put( - RangerDefines.SEARCH_FILTER_SERVICE_NAME, rangerAuthorizationPlugin.rangerServiceName); + searchFilters.put(SearchFilter.SERVICE_NAME, rangerServiceName); searchFilters.put(SearchFilter.POLICY_LABELS_PARTIAL, MANAGED_BY_GRAVITINO); for (int i = 0; i < nsMetadataObj.size(); i++) { searchFilters.put(policySearchKeys.get(i), nsMetadataObj.get(i)); - preciseFilters.put(policyPreciseFilterKeys.get(i), nsMetadataObj.get(i)); + preciseFilters.put(policyResourceDefines.get(i), nsMetadataObj.get(i)); } try { - List policies = - rangerAuthorizationPlugin.rangerClient.findPolicies(searchFilters); + List policies = rangerClient.findPolicies(searchFilters); if (!policies.isEmpty()) { /** @@ -357,10 +391,7 @@ public RangerPolicy findManagedPolicy(MetadataObject metadataObject) protected boolean checkRangerRole(String roleName) throws AuthorizationPluginException { try { - rangerAuthorizationPlugin.rangerClient.getRole( - roleName, - rangerAuthorizationPlugin.rangerAdminName, - rangerAuthorizationPlugin.rangerServiceName); + rangerClient.getRole(roleName, rangerAdminName, rangerServiceName); } catch (RangerServiceException e) { throw new AuthorizationPluginException(e); } @@ -377,7 +408,7 @@ protected GrantRevokeRoleRequest createGrantRevokeRoleRequest( GrantRevokeRoleRequest roleRequest = new GrantRevokeRoleRequest(); roleRequest.setUsers(users); roleRequest.setGroups(groups); - roleRequest.setGrantor(rangerAuthorizationPlugin.rangerAdminName); + roleRequest.setGrantor(rangerAdminName); roleRequest.setTargetRoles(Sets.newHashSet(roleName)); return roleRequest; } @@ -386,11 +417,7 @@ protected GrantRevokeRoleRequest createGrantRevokeRoleRequest( protected RangerRole createRangerRoleIfNotExists(String roleName) { RangerRole rangerRole = null; try { - rangerRole = - rangerAuthorizationPlugin.rangerClient.getRole( - roleName, - rangerAuthorizationPlugin.rangerAdminName, - rangerAuthorizationPlugin.rangerServiceName); + rangerRole = rangerClient.getRole(roleName, rangerAdminName, rangerServiceName); } catch (RangerServiceException e) { // ignore exception, If the role does not exist, then create it. LOG.warn("The role({}) does not exist in the Ranger!", roleName); @@ -398,8 +425,7 @@ protected RangerRole createRangerRoleIfNotExists(String roleName) { try { if (rangerRole == null) { rangerRole = new RangerRole(roleName, RangerHelper.MANAGED_BY_GRAVITINO, null, null, null); - rangerAuthorizationPlugin.rangerClient.createRole( - rangerAuthorizationPlugin.rangerServiceName, rangerRole); + rangerClient.createRole(rangerServiceName, rangerRole); } } catch (RangerServiceException e) { throw new RuntimeException(e); @@ -416,7 +442,11 @@ protected void updatePolicyOwner(RangerPolicy policy, Owner preOwner, Owner newO return policyItem.getAccesses().stream() .allMatch( policyItemAccess -> { - return ownerPrivileges.contains(policyItemAccess.getType()); + return ownerPrivileges.stream() + .anyMatch( + ownerPrivilege -> { + return ownerPrivilege.equals(policyItemAccess.getType()); + }); }); }) .collect(Collectors.toList()); @@ -461,7 +491,9 @@ protected void updatePolicyOwner(RangerPolicy policy, Owner preOwner, Owner newO // Add lost owner's privilege to the policy ownerPrivilege -> { RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); - policyItem.getAccesses().add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege)); + policyItem + .getAccesses() + .add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege.toString())); if (newOwner != null) { if (newOwner.type() == Owner.Type.USER) { policyItem.getUsers().add(newOwner.name()); @@ -486,7 +518,7 @@ private List getMetadataObjectNames(MetadataObject metadataObject) { protected RangerPolicy createPolicyAddResources(MetadataObject metadataObject) { RangerPolicy policy = new RangerPolicy(); - policy.setService(rangerAuthorizationPlugin.rangerServiceName); + policy.setService(rangerServiceName); policy.setName(metadataObject.fullName()); policy.setPolicyLabels(Lists.newArrayList(RangerHelper.MANAGED_BY_GRAVITINO)); @@ -495,7 +527,7 @@ protected RangerPolicy createPolicyAddResources(MetadataObject metadataObject) { for (int i = 0; i < nsMetadataObject.size(); i++) { RangerPolicy.RangerPolicyResource policyResource = new RangerPolicy.RangerPolicyResource(nsMetadataObject.get(i)); - policy.getResources().put(policyPreciseFilterKeys.get(i), policyResource); + policy.getResources().put(policyResourceDefines.get(i), policyResource); } return policy; } @@ -507,7 +539,9 @@ protected RangerPolicy addOwnerToNewPolicy(MetadataObject metadataObject, Owner ownerPrivilege -> { // Each owner's privilege will create one RangerPolicyItemAccess in the policy RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); - policyItem.getAccesses().add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege)); + policyItem + .getAccesses() + .add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege.toString())); if (newOwner != null) { if (newOwner.type() == Owner.Type.USER) { policyItem.getUsers().add(newOwner.name()); diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilege.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilege.java new file mode 100644 index 00000000000..931c34ab5e4 --- /dev/null +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivilege.java @@ -0,0 +1,81 @@ +/* + * 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; + +/** RangerPrivilege interface is used to define the Ranger privileges. */ +public interface RangerPrivilege { + String toString(); + + boolean equals(String value); + + /** Ranger Hive privileges enumeration. */ + enum RangerHivePrivilege implements RangerPrivilege { + ALL("all"), + SELECT("select"), + UPDATE("update"), + CREATE("create"), + DROP("drop"), + ALTER("alter"), + INDEX("index"), + LOCK("lock"), + READ("read"), + WRITE("write"), + REPLADMIN("repladmin"), + SERVICEADMIN("serviceadmin"); + + private final String string; // Access a type in the Ranger policy item + + RangerHivePrivilege(String str) { + this.string = str; + } + + @Override + public String toString() { + return string; + } + + @Override + public boolean equals(String value) { + return this.string.equalsIgnoreCase(value); + } + } + + /** Ranger HDFS privileges enumeration. */ + enum RangerHdfsPrivilege implements RangerPrivilege { + READ("read"), + WRITE("write"), + EXECUTE("execute"); + + private final String string; // Access a type in the Ranger policy item + + RangerHdfsPrivilege(String str) { + this.string = str; + } + + @Override + public String toString() { + return string; + } + + @Override + public boolean equals(String value) { + return this.string.equalsIgnoreCase(value); + } + } +} diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java new file mode 100644 index 00000000000..475ec6eda62 --- /dev/null +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java @@ -0,0 +1,42 @@ +/* + * 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.collect.Lists; +import java.util.List; + +public class RangerPrivileges { + static List>> allRangerPrivilege = + Lists.newArrayList( + RangerPrivilege.RangerHivePrivilege.class, RangerPrivilege.RangerHdfsPrivilege.class); + + public static RangerPrivilege valueOf(String string) { + RangerHelper.check(string != null, "Privilege name string cannot be null!"); + + String strPrivilege = string.trim().toLowerCase(); + for (Class> enumClass : allRangerPrivilege) { + for (Enum privilege : enumClass.getEnumConstants()) { + if (((RangerPrivilege) privilege).equals(strPrivilege)) { + return (RangerPrivilege) privilege; + } + } + } + throw new IllegalArgumentException("Unknown privilege string: " + string); + } +} diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java index aa11ca215a5..63e49ba896c 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java @@ -18,72 +18,35 @@ */ package org.apache.gravitino.authorization.ranger.reference; -import org.apache.ranger.plugin.util.SearchFilter; - public class RangerDefines { - // In the Ranger 2.4.0 - // apache/ranger/security-admin/src/main/java/org/apache/ranger/service/RangerServiceDefService.java:L43 - public static final String IMPLICIT_CONDITION_EXPRESSION_NAME = "_expression"; - - // In the Ranger 2.4.0 - // apache/ranger/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java:L159 - // Search filter constants - public static final String SEARCH_FILTER_SERVICE_NAME = SearchFilter.SERVICE_NAME; - // Hive resource database name - public static final String RESOURCE_DATABASE = "database"; - // Hive resource table name - public static final String RESOURCE_TABLE = "table"; - // Hive resource column name - public static final String RESOURCE_COLUMN = "column"; - // HDFS resource path name - public static final String RESOURCE_PATH = "path"; - // Search filter prefix database constants - public static final String SEARCH_FILTER_DATABASE = - SearchFilter.RESOURCE_PREFIX + RESOURCE_DATABASE; - // Search filter prefix table constants - public static final String SEARCH_FILTER_TABLE = SearchFilter.RESOURCE_PREFIX + RESOURCE_TABLE; - // Search filter prefix column constants - public static final String SEARCH_FILTER_COLUMN = SearchFilter.RESOURCE_PREFIX + RESOURCE_COLUMN; - // Search filter prefix file path constants - public static final String SEARCH_FILTER_PATH = SearchFilter.RESOURCE_PREFIX + RESOURCE_PATH; // Ranger service type HDFS public static final String SERVICE_TYPE_HDFS = "hdfs"; // HDFS service type // Ranger service type Hive public static final String SERVICE_TYPE_HIVE = "hive"; // Hive service type + + // In the Ranger 2.4.0 + // agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java // {OWNER}: resource owner user variable public static final String OWNER_USER = "{OWNER}"; // {USER}: current user variable public static final String CURRENT_USER = "{USER}"; // public group public static final String PUBLIC_GROUP = "public"; - // Read access type in the HDFS - public static final String ACCESS_TYPE_HDFS_READ = "read"; - // Write access type in the HDFS - public static final String ACCESS_TYPE_HDFS_WRITE = "write"; - // execute access type in the HDFS - public static final String ACCESS_TYPE_HDFS_EXECUTE = "execute"; - // All access type in the Hive - public static final String ACCESS_TYPE_HIVE_ALL = "all"; - // Select access type in the Hive - public static final String ACCESS_TYPE_HIVE_SELECT = "select"; - // update access type in the Hive - public static final String ACCESS_TYPE_HIVE_UPDATE = "update"; - // create access type in the Hive - public static final String ACCESS_TYPE_HIVE_CREATE = "create"; - // drop access type in the Hive - public static final String ACCESS_TYPE_HIVE_DROP = "drop"; - // alter access type in the Hive - public static final String ACCESS_TYPE_HIVE_ALTER = "alter"; - // index access type in the Hive - public static final String ACCESS_TYPE_HIVE_INDEX = "index"; - // lock access type in the Hive - public static final String ACCESS_TYPE_HIVE_LOCK = "lock"; - // read access type in the Hive - public static final String ACCESS_TYPE_HIVE_READ = "read"; - // write access type in the Hive - public static final String ACCESS_TYPE_HIVE_WRITE = "write"; - // repladmin access type in the Hive - public static final String ACCESS_TYPE_HIVE_REPLADMIN = "repladmin"; - // serviceadmin access type in the Hive - public static final String ACCESS_TYPE_HIVE_SERVICEADMIN = "serviceadmin"; + + public enum PolicyResource { + // In the Ranger 2.4.0 agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json + DATABASE("database"), + TABLE("table"), + COLUMN("column"); + + private final String string; + + PolicyResource(String str) { + this.string = str; + } + + public String toString() { + return string; + } + } } diff --git a/authorizations/authorization-ranger/src/main/resources/authorization-defs/authorization-hive.properties.template b/authorizations/authorization-ranger/src/main/resources/authorization-defs/authorization-hive.properties.template new file mode 100644 index 00000000000..d261d6499c8 --- /dev/null +++ b/authorizations/authorization-ranger/src/main/resources/authorization-defs/authorization-hive.properties.template @@ -0,0 +1,32 @@ +# +# 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. +# +# Ranger Hive privileges enum RangerHivePrivilege: create, alter, drop, index, lock, select, insert, update, delete, read, write, all +# defined in the `authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java` +# Case insensitive +gravitino.authorization.owner.privileges = all + +# Gravitino privileges defined in the `api/src/main/java/org/apache/gravitino/authorization/Privilege.java` +# authorization.privilege.mapping. = ,,... +gravitino.authorization.privilege.mapping.CREATE_SCHEMA = create +gravitino.authorization.privilege.mapping.CREATE_TABLE = create +gravitino.authorization.privilege.mapping.SELECT_TABLE = read,select +gravitino.authorization.privilege.mapping.MODIFY_TABLE = update,alter,write + +# Ranger policy resource defines (fixed configuration, do not change) +gravitino.authorization.ranger.policy.resource.defines = database,table,column \ No newline at end of file diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/AuthorizationConfigTest.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/AuthorizationConfigTest.java new file mode 100644 index 00000000000..28c10273fc9 --- /dev/null +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/AuthorizationConfigTest.java @@ -0,0 +1,80 @@ +/* + * 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 static org.apache.gravitino.authorization.Privilege.Name.CREATE_SCHEMA; +import static org.apache.gravitino.authorization.Privilege.Name.CREATE_TABLE; +import static org.apache.gravitino.authorization.Privilege.Name.MODIFY_TABLE; +import static org.apache.gravitino.authorization.Privilege.Name.SELECT_TABLE; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.collect.ImmutableSet; + +public class AuthorizationConfigTest { + @Test + public void testErrorHiveProperties() { + AuthorizationConfig authorizationConfig = new AuthorizationConfig(); + String propertyFilePath = + String.format("/authorization-defs/authorization-%s.properties", "hive"); + URL resourceUrl = AuthorizationConfigTest.class.getResource(propertyFilePath); + try { + if (resourceUrl != null) { + Properties properties = + authorizationConfig.loadPropertiesFromFile(new File(resourceUrl.getPath())); + authorizationConfig.loadFromProperties(properties); + } + } catch (IOException e) { + throw new IllegalArgumentException( + "Failed to load authorization config from resource " + resourceUrl, e); + } + + RangerHelper rangerHelper = new RangerHelper(authorizationConfig); + Set ownerPrivileges = rangerHelper.getOwnerPrivileges(); + Set createSchemaPrivileges = rangerHelper.translatePrivilege(CREATE_SCHEMA); + Set createTablePrivileges = rangerHelper.translatePrivilege(CREATE_TABLE); + Set selectTablePrivileges = rangerHelper.translatePrivilege(SELECT_TABLE); + Set modifyTablePrivileges = rangerHelper.translatePrivilege(MODIFY_TABLE); + + Assertions.assertEquals( + ownerPrivileges, ImmutableSet.of(RangerPrivilege.RangerHivePrivilege.ALL.toString())); + Assertions.assertEquals( + createSchemaPrivileges, + ImmutableSet.of(RangerPrivilege.RangerHivePrivilege.CREATE.toString())); + Assertions.assertEquals( + createTablePrivileges, + ImmutableSet.of(RangerPrivilege.RangerHivePrivilege.CREATE.toString())); + Assertions.assertEquals( + selectTablePrivileges, + ImmutableSet.of( + RangerPrivilege.RangerHivePrivilege.READ.toString(), + RangerPrivilege.RangerHivePrivilege.SELECT.toString())); + Assertions.assertEquals( + modifyTablePrivileges, + ImmutableSet.of( + RangerPrivilege.RangerHivePrivilege.UPDATE.toString(), + RangerPrivilege.RangerHivePrivilege.ALTER.toString(), + RangerPrivilege.RangerHivePrivilege.WRITE.toString())); + } +} 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 79f66ef287a..67a04524425 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,7 +19,9 @@ 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.RESOURCE_DATABASE; 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.ImmutableMap; @@ -46,6 +48,7 @@ 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.RangerPrivilege; import org.apache.gravitino.authorization.ranger.reference.RangerDefines; import org.apache.gravitino.connector.AuthorizationPropertiesMeta; import org.apache.gravitino.integration.test.container.ContainerSuite; @@ -117,7 +120,12 @@ public static void setup() { RangerContainer.rangerPassword, AuthorizationPropertiesMeta.RANGER_SERVICE_NAME, RangerITEnv.RANGER_HIVE_REPO_NAME)); - rangerPolicyHelper = new RangerHelper(rangerAuthPlugin, "hive"); + rangerPolicyHelper = + new RangerHelper( + "hive", + rangerClient, + RangerContainer.rangerUserName, + RangerITEnv.RANGER_HIVE_REPO_NAME); // Create hive connection String url = @@ -280,8 +288,8 @@ static void createHivePolicy(List metaObjects, String roleName) { new RangerPolicy.RangerPolicyResource(metaObjects.get(i)); policyResourceMap.put( i == 0 - ? RangerDefines.RESOURCE_DATABASE - : i == 1 ? RangerDefines.RESOURCE_TABLE : RangerDefines.RESOURCE_COLUMN, + ? RangerITEnv.RESOURCE_DATABASE + : i == 1 ? RangerITEnv.RESOURCE_TABLE : RangerITEnv.RESOURCE_COLUMN, policyResource); } @@ -289,7 +297,8 @@ static void createHivePolicy(List metaObjects, String roleName) { policyItem.setGroups(Arrays.asList(RangerDefines.PUBLIC_GROUP)); policyItem.setAccesses( Arrays.asList( - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HIVE_SELECT))); + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHivePrivilege.SELECT.toString()))); RangerITEnv.updateOrCreateRangerPolicy( RangerDefines.SERVICE_TYPE_HIVE, RangerITEnv.RANGER_HIVE_REPO_NAME, @@ -1132,8 +1141,8 @@ private void verifyOwnerInRanger( .getResources() .get( i == 0 - ? RangerDefines.RESOURCE_DATABASE - : i == 1 ? RangerDefines.RESOURCE_TABLE : RangerDefines.RESOURCE_COLUMN) + ? RangerITEnv.RESOURCE_DATABASE + : i == 1 ? RangerITEnv.RESOURCE_TABLE : RangerITEnv.RESOURCE_COLUMN) .getValues() .get(0)); } @@ -1195,69 +1204,6 @@ private void verifyOwnerInRanger(MetadataObject metadataObject, List inc verifyOwnerInRanger(metadataObject, includeUsers, null, null, null); } - /** Currently we only test Ranger Hive, So wo Allow anyone to visit HDFS */ - static void allowAnyoneAccessHDFS() { - String policyName = currentFunName(); - try { - if (null != RangerITEnv.rangerClient.getPolicy(RangerDefines.SERVICE_TYPE_HDFS, policyName)) { - return; - } - } catch (RangerServiceException e) { - // If the policy doesn't exist, we will create it - } - - Map policyResourceMap = - ImmutableMap.of(RangerDefines.RESOURCE_PATH, new RangerPolicy.RangerPolicyResource("/*")); - RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); - policyItem.setUsers(Arrays.asList(RangerDefines.CURRENT_USER)); - policyItem.setAccesses( - Arrays.asList( - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_READ), - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_WRITE), - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_EXECUTE))); - RangerITEnv.updateOrCreateRangerPolicy( - RangerDefines.SERVICE_TYPE_HDFS, - RangerITEnv.RANGER_HDFS_REPO_NAME, - policyName, - policyResourceMap, - Collections.singletonList(policyItem)); - } - - /** - * Hive must have this policy Allow anyone can access information schema to show `database`, - * `tables` and `columns` - */ - static void allowAnyoneAccessInformationSchema() { - String policyName = currentFunName(); - try { - if (null != RangerITEnv.rangerClient.getPolicy(RangerDefines.SERVICE_TYPE_HIVE, policyName)) { - return; - } - } catch (RangerServiceException e) { - // If the policy doesn't exist, we will create it - } - - Map policyResourceMap = - ImmutableMap.of( - RangerDefines.RESOURCE_DATABASE, - new RangerPolicy.RangerPolicyResource("information_schema"), - RangerDefines.RESOURCE_TABLE, - new RangerPolicy.RangerPolicyResource("*"), - RangerDefines.RESOURCE_COLUMN, - new RangerPolicy.RangerPolicyResource("*")); - RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); - policyItem.setGroups(Arrays.asList(RangerDefines.PUBLIC_GROUP)); - policyItem.setAccesses( - Arrays.asList( - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HIVE_SELECT))); - RangerITEnv.updateOrCreateRangerPolicy( - RangerDefines.SERVICE_TYPE_HIVE, - RangerITEnv.RANGER_HIVE_REPO_NAME, - policyName, - policyResourceMap, - Collections.singletonList(policyItem)); - } - @Test public void testCreateDatabase() throws Exception { String dbName = currentFunName().toLowerCase(); // Hive database name is case-insensitive @@ -1265,12 +1211,13 @@ public void testCreateDatabase() throws Exception { // Only allow admin user to operation database `db1` // Other users can't see the database `db1` Map policyResourceMap = - ImmutableMap.of( - RangerDefines.RESOURCE_DATABASE, new RangerPolicy.RangerPolicyResource(dbName)); + ImmutableMap.of(RESOURCE_DATABASE, new RangerPolicy.RangerPolicyResource(dbName)); RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); policyItem.setUsers(Arrays.asList(adminUser)); policyItem.setAccesses( - Arrays.asList(new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HIVE_ALL))); + Arrays.asList( + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHivePrivilege.ALL.toString()))); RangerITEnv.updateOrCreateRangerPolicy( RangerDefines.SERVICE_TYPE_HIVE, RangerITEnv.RANGER_HIVE_REPO_NAME, @@ -1300,7 +1247,9 @@ public void testCreateDatabase() throws Exception { // Allow anonymous user to see the database `db1` policyItem.setUsers(Arrays.asList(adminUser, anonymousUser)); policyItem.setAccesses( - Arrays.asList(new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HIVE_ALL))); + Arrays.asList( + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHivePrivilege.ALL.toString()))); RangerITEnv.updateOrCreateRangerPolicy( RangerDefines.SERVICE_TYPE_HIVE, RangerITEnv.RANGER_HIVE_REPO_NAME, 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 2808a2b796d..4c39085cd52 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 @@ -29,12 +29,13 @@ import java.util.stream.Collectors; import org.apache.gravitino.authorization.Role; import org.apache.gravitino.authorization.ranger.RangerAuthorizationPlugin; +import org.apache.gravitino.authorization.ranger.RangerClientExtend; import org.apache.gravitino.authorization.ranger.RangerHelper; +import org.apache.gravitino.authorization.ranger.RangerPrivilege; import org.apache.gravitino.authorization.ranger.reference.RangerDefines; import org.apache.gravitino.integration.test.container.ContainerSuite; import org.apache.gravitino.integration.test.container.HiveContainer; import org.apache.gravitino.integration.test.container.TrinoContainer; -import org.apache.ranger.RangerClient; import org.apache.ranger.RangerServiceException; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerRole; @@ -53,10 +54,27 @@ public class RangerITEnv { private static final String RANGER_HIVE_TYPE = "hive"; protected static final String RANGER_HDFS_REPO_NAME = "hdfsDev"; private static final String RANGER_HDFS_TYPE = "hdfs"; - protected static RangerClient rangerClient; + protected static RangerClientExtend rangerClient; private static volatile boolean initRangerService = false; private static final ContainerSuite containerSuite = ContainerSuite.getInstance(); + // Hive resource database name + public static final String RESOURCE_DATABASE = "database"; + // Hive resource table name + public static final String RESOURCE_TABLE = "table"; + // Hive resource column name + public static final String RESOURCE_COLUMN = "column"; + // HDFS resource path name + public static final String RESOURCE_PATH = "path"; + public static final String SEARCH_FILTER_DATABASE = + SearchFilter.RESOURCE_PREFIX + RESOURCE_DATABASE; + // Search filter prefix table constants + public static final String SEARCH_FILTER_TABLE = SearchFilter.RESOURCE_PREFIX + RESOURCE_TABLE; + // Search filter prefix column constants + public static final String SEARCH_FILTER_COLUMN = SearchFilter.RESOURCE_PREFIX + RESOURCE_COLUMN; + // Search filter prefix file path constants + public static final String SEARCH_FILTER_PATH = SearchFilter.RESOURCE_PREFIX + RESOURCE_PATH; + public static void setup() { containerSuite.startRangerContainer(); rangerClient = containerSuite.getRangerContainer().rangerClient; @@ -101,14 +119,17 @@ static void allowAnyoneAccessHDFS() { } Map policyResourceMap = - ImmutableMap.of(RangerDefines.RESOURCE_PATH, new RangerPolicy.RangerPolicyResource("/*")); + ImmutableMap.of("path", new RangerPolicy.RangerPolicyResource("/*")); RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); policyItem.setUsers(Arrays.asList(RangerDefines.CURRENT_USER)); policyItem.setAccesses( Arrays.asList( - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_READ), - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_WRITE), - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HDFS_EXECUTE))); + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHdfsPrivilege.READ.toString()), + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHdfsPrivilege.WRITE.toString()), + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHdfsPrivilege.EXECUTE.toString()))); updateOrCreateRangerPolicy( RangerDefines.SERVICE_TYPE_HDFS, RANGER_HDFS_REPO_NAME, @@ -134,17 +155,18 @@ static void allowAnyoneAccessInformationSchema() { Map policyResourceMap = ImmutableMap.of( - RangerDefines.RESOURCE_DATABASE, + "database", new RangerPolicy.RangerPolicyResource("information_schema"), - RangerDefines.RESOURCE_TABLE, + "table", new RangerPolicy.RangerPolicyResource("*"), - RangerDefines.RESOURCE_COLUMN, + "column", new RangerPolicy.RangerPolicyResource("*")); RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); policyItem.setGroups(Arrays.asList(RangerDefines.PUBLIC_GROUP)); policyItem.setAccesses( Arrays.asList( - new RangerPolicy.RangerPolicyItemAccess(RangerDefines.ACCESS_TYPE_HIVE_SELECT))); + new RangerPolicy.RangerPolicyItemAccess( + RangerPrivilege.RangerHivePrivilege.SELECT.toString()))); updateOrCreateRangerPolicy( RangerDefines.SERVICE_TYPE_HIVE, RANGER_HIVE_REPO_NAME, @@ -176,7 +198,7 @@ public void createRangerTrinoRepository(String trinoIp) { Assertions.assertNotNull(createdService); Map filter = - ImmutableMap.of(RangerDefines.SEARCH_FILTER_SERVICE_NAME, RANGER_TRINO_REPO_NAME); + ImmutableMap.of(SearchFilter.SERVICE_NAME, RANGER_TRINO_REPO_NAME); List services = rangerClient.findServices(filter); Assertions.assertEquals(RANGER_TRINO_TYPE, services.get(0).getType()); Assertions.assertEquals(RANGER_TRINO_REPO_NAME, services.get(0).getName()); @@ -223,7 +245,7 @@ public static void createRangerHiveRepository(String hiveIp, boolean cleanAllPol Assertions.assertNotNull(createdService); Map filter = - ImmutableMap.of(RangerDefines.SEARCH_FILTER_SERVICE_NAME, RANGER_HIVE_REPO_NAME); + ImmutableMap.of(SearchFilter.SERVICE_NAME, RANGER_HIVE_REPO_NAME); List services = rangerClient.findServices(filter); Assertions.assertEquals(RANGER_HIVE_TYPE, services.get(0).getType()); Assertions.assertEquals(RANGER_HIVE_REPO_NAME, services.get(0).getName()); @@ -280,7 +302,7 @@ public static void createRangerHdfsRepository(String hdfsIp, boolean cleanAllPol Assertions.assertNotNull(createdService); Map filter = - ImmutableMap.of(RangerDefines.SEARCH_FILTER_SERVICE_NAME, RANGER_HDFS_REPO_NAME); + ImmutableMap.of(SearchFilter.SERVICE_NAME, RANGER_HDFS_REPO_NAME); List services = rangerClient.findServices(filter); Assertions.assertEquals(RANGER_HDFS_TYPE, services.get(0).getType()); Assertions.assertEquals(RANGER_HDFS_REPO_NAME, services.get(0).getName()); @@ -436,26 +458,26 @@ protected static void updateOrCreateRangerPolicy( Map resourceFilter = new HashMap<>(); // use to match the precise policy Map policyFilter = new HashMap<>(); - policyFilter.put(RangerDefines.SEARCH_FILTER_SERVICE_NAME, serviceName); + policyFilter.put(SearchFilter.SERVICE_NAME, serviceName); policyFilter.put(SearchFilter.POLICY_LABELS_PARTIAL, RangerHelper.MANAGED_BY_GRAVITINO); final int[] index = {0}; policyResourceMap.forEach( (k, v) -> { if (type.equals(RANGER_HIVE_TYPE)) { if (index[0] == 0) { - policyFilter.put(RangerDefines.SEARCH_FILTER_DATABASE, v.getValues().get(0)); - resourceFilter.put(RangerDefines.RESOURCE_DATABASE, v.getValues().get(0)); + policyFilter.put(SEARCH_FILTER_DATABASE, v.getValues().get(0)); + resourceFilter.put(RESOURCE_DATABASE, v.getValues().get(0)); } else if (index[0] == 1) { - policyFilter.put(RangerDefines.SEARCH_FILTER_TABLE, v.getValues().get(0)); - resourceFilter.put(RangerDefines.RESOURCE_TABLE, v.getValues().get(0)); + policyFilter.put(SEARCH_FILTER_TABLE, v.getValues().get(0)); + resourceFilter.put(RESOURCE_TABLE, v.getValues().get(0)); } else if (index[0] == 2) { - policyFilter.put(RangerDefines.SEARCH_FILTER_COLUMN, v.getValues().get(0)); - resourceFilter.put(RangerDefines.RESOURCE_TABLE, v.getValues().get(0)); + policyFilter.put(SEARCH_FILTER_COLUMN, v.getValues().get(0)); + resourceFilter.put(RESOURCE_TABLE, v.getValues().get(0)); } index[0]++; } else if (type.equals(RANGER_HDFS_TYPE)) { - policyFilter.put(RangerDefines.SEARCH_FILTER_PATH, v.getValues().get(0)); - resourceFilter.put(RangerDefines.RESOURCE_PATH, v.getValues().get(0)); + policyFilter.put(SEARCH_FILTER_PATH, v.getValues().get(0)); + resourceFilter.put(RESOURCE_PATH, v.getValues().get(0)); } }); try { @@ -512,8 +534,7 @@ protected static void updateOrCreateRangerPolicy( protected static void cleanAllPolicy(String serviceName) { try { List policies = - rangerClient.findPolicies( - ImmutableMap.of(RangerDefines.SEARCH_FILTER_SERVICE_NAME, serviceName)); + rangerClient.findPolicies(ImmutableMap.of(SearchFilter.SERVICE_NAME, serviceName)); for (RangerPolicy policy : policies) { rangerClient.deletePolicy(policy.getId()); } diff --git a/authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive.properties b/authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive.properties new file mode 100644 index 00000000000..1bfd8fd58e5 --- /dev/null +++ b/authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive.properties @@ -0,0 +1,32 @@ +# +# 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. +# +# Ranger Hive privileges enum RangerHivePrivilege: create, alter, drop, index, lock, select, insert, update, delete, read, write, all +# defined in the `authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/RangerDefines.java` +# Case insensitive +gravitino.authorization.owner.privileges = all + +# Gravitino privileges defined in the `api/src/main/java/org/apache/gravitino/authorization/Privilege.java` +# authorization.privilege.mapping. = ,,... +gravitino.authorization.privilege.mapping.CREATE_SCHEMA = create +gravitino.authorization.privilege.mapping.CREATE_TABLE = create +gravitino.authorization.privilege.mapping.SELECT_TABLE = read, select +gravitino.authorization.privilege.mapping.MODIFY_TABLE = update, alter , WrIte + +# Ranger policy resource defines (fixed configuration, do not change) +gravitino.authorization.ranger.policy.resource.defines = database, TABLE , column \ No newline at end of file diff --git a/integration-test-common/build.gradle.kts b/integration-test-common/build.gradle.kts index a25ad4cff8f..449c38efce8 100644 --- a/integration-test-common/build.gradle.kts +++ b/integration-test-common/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { testImplementation(project(":core")) testImplementation(project(":server")) testImplementation(project(":server-common")) + testImplementation(project(":authorizations:authorization-ranger")) testImplementation(libs.bundles.jetty) testImplementation(libs.bundles.jersey) testImplementation(libs.bundles.jwt) diff --git a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/RangerContainer.java b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/RangerContainer.java index 54b2afc0c77..19270ad19b0 100644 --- a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/RangerContainer.java +++ b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/RangerContainer.java @@ -25,7 +25,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import org.apache.ranger.RangerClient; +import org.apache.gravitino.authorization.ranger.RangerClientExtend; import org.apache.ranger.RangerServiceException; import org.rnorth.ducttape.Preconditions; import org.slf4j.Logger; @@ -38,7 +38,7 @@ public class RangerContainer extends BaseContainer { public static final String DEFAULT_IMAGE = System.getenv("GRAVITINO_CI_RANGER_DOCKER_IMAGE"); public static final String HOST_NAME = "gravitino-ci-ranger"; public static final int RANGER_SERVER_PORT = 6080; - public RangerClient rangerClient; + public RangerClientExtend rangerClient; private String rangerUrl; /** @@ -83,7 +83,7 @@ public void start() { super.start(); rangerUrl = String.format("http://localhost:%s", this.getMappedPort(RANGER_SERVER_PORT)); - rangerClient = new RangerClient(rangerUrl, authType, rangerUserName, rangerPassword, null); + rangerClient = new RangerClientExtend(rangerUrl, authType, rangerUserName, rangerPassword); Preconditions.check("Ranger container startup failed!", checkContainerStatus(10)); }