Repository: sentry Updated Branches: refs/heads/master 6d2ad5fa5 -> bee44c28a
SENTRY-2224: Support SHOW GRANT on HIVE_OBJECT (Arjun Mishra, reviewed by Sergio Pena) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/bee44c28 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/bee44c28 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/bee44c28 Branch: refs/heads/master Commit: bee44c28adac869ccf9972854d31e88adcc5f251 Parents: 6d2ad5f Author: Sergio Pena <[email protected]> Authored: Tue Jun 19 17:43:28 2018 -0500 Committer: Sergio Pena <[email protected]> Committed: Tue Jun 19 17:43:28 2018 -0500 ---------------------------------------------------------------------- .../SentryHiveAuthorizationTaskFactoryImpl.java | 59 +++-- .../authz/DefaultSentryAccessController.java | 78 +++++++ .../TestSentryHiveAuthorizationTaskFactory.java | 46 ++++ .../service/thrift/SentryObjectPrivileges.java | 54 +++++ .../thrift/SentryPolicyServiceClient.java | 22 ++ .../SentryPolicyServiceClientDefaultImpl.java | 33 ++- .../tests/e2e/dbprovider/TestShowGrants.java | 227 +++++++++++++++++++ 7 files changed, 500 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java index 0518938..660bef1 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hive.SentryHiveConstants; import org.apache.hadoop.hive.conf.HiveConf; @@ -188,30 +189,56 @@ public class SentryHiveAuthorizationTaskFactoryImpl implements HiveAuthorization HashSet<WriteEntity> outputs) throws SemanticException { SentryHivePrivilegeObjectDesc privHiveObj = null; - ASTNode principal = (ASTNode) ast.getChild(0); + PrincipalDesc principalDesc = null; PrincipalType type = null; + + ASTNode principal = (ASTNode) ast.getChild(0); switch (principal.getType()) { - case HiveParser.TOK_USER: - type = PrincipalType.USER; - break; - case HiveParser.TOK_GROUP: - type = PrincipalType.GROUP; - break; - case HiveParser.TOK_ROLE: - type = PrincipalType.ROLE; - break; - default: - type = PrincipalType.USER; + case HiveParser.TOK_USER: + type = PrincipalType.USER; + break; + case HiveParser.TOK_GROUP: + type = PrincipalType.GROUP; + break; + case HiveParser.TOK_ROLE: + type = PrincipalType.ROLE; + break; + case HiveParser.TOK_PRIV_OBJECT_COL: + //Set type as null for SHOW GRANT ON <hive_object> + type = null; + break; } - if (type != PrincipalType.ROLE) { + if (type != null && type != PrincipalType.ROLE) { String msg = SentryHiveConstants.SHOW_NOT_SUPPORTED_FOR_PRINCIPAL + type; throw new SemanticException(msg); } - String principalName = BaseSemanticAnalyzer.unescapeIdentifier(principal.getChild(0).getText()); - PrincipalDesc principalDesc = new PrincipalDesc(principalName, type); + + if(type != null) { + String principalName = BaseSemanticAnalyzer + .unescapeIdentifier(principal.getChild(0).getText()); + principalDesc = new PrincipalDesc(principalName, type); + } else { + /** + * Commands like SHOW GRANT ON <hive_object + * Eg: ASTNode structure: TOK_SHOW_GRANT -> TOK_PRIV_OBJECT_COL -> TOK_TABLE_TYPE -> TOK_TABNAME -> <hive_object> + */ + privHiveObj = analyzePrivilegeObject(principal); + if(privHiveObj == null) { + String msg = + SentryHiveConstants.SHOW_NOT_SUPPORTED_FOR_PRINCIPAL + "unspecified object name"; + throw new SemanticException(msg); + } + //Principal name is list of all users or roles granted privilege to the object + principalDesc = new PrincipalDesc(StringUtils.EMPTY, type); + } // Partition privileges are not supported by Sentry - if (ast.getChildCount() > 1) { + if (type != null && ast.getChildCount() > 1) { + /** + * Support for SHOW GRANT ROLE/USER/GROUP <name> ON <hive_o + * bject> + * Eg: ASTNode structure: TOK_SHOW_GRANT -> {TOK_ROLE/TOK_GROUP/TOK_USER, TOK_PRIV_OBJECT_COL} -> TOK_TABLE_TYPE -> TOK_TABNAME -> <hive_object> + */ ASTNode child = (ASTNode) ast.getChild(1); if (child.getToken().getType() == HiveParser.TOK_PRIV_OBJECT_COL) { privHiveObj = analyzePrivilegeObject(child); http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryAccessController.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryAccessController.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryAccessController.java index 321701d..318c1e8 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryAccessController.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryAccessController.java @@ -17,8 +17,10 @@ package org.apache.sentry.binding.hive.authz; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hive.SentryHiveConstants; @@ -37,6 +39,9 @@ import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilege; import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeInfo; import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject; import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveRoleGrant; +import org.apache.sentry.api.service.thrift.SentryObjectPrivileges; +import org.apache.sentry.api.service.thrift.TSentryAuthorizable; +import org.apache.sentry.api.service.thrift.TSentryPrivilegeMap; import org.apache.sentry.binding.hive.SentryOnFailureHookContext; import org.apache.sentry.binding.hive.SentryOnFailureHookContextImpl; import org.apache.sentry.binding.hive.authz.HiveAuthzBinding.HiveHook; @@ -201,6 +206,15 @@ public class DefaultSentryAccessController extends SentryHiveAccessController { @Override public List<HivePrivilegeInfo> showPrivileges(HivePrincipal principal, HivePrivilegeObject privObj) throws HiveAuthzPluginException, HiveAccessControlException { + if(principal.getName().isEmpty()) { + return showPriviliegesForObject(privObj); + } else { + return showPrivilegesByPrincipal(principal, privObj); + } + } + + public List<HivePrivilegeInfo> showPrivilegesByPrincipal(HivePrincipal principal, + HivePrivilegeObject privObj) throws HiveAuthzPluginException, HiveAccessControlException { if (principal.getType() != HivePrincipalType.ROLE && principal.getType() != HivePrincipalType.USER) { String msg = SentryHiveConstants.SHOW_NOT_SUPPORTED_FOR_PRINCIPAL + principal.getType(); @@ -255,6 +269,70 @@ public class DefaultSentryAccessController extends SentryHiveAccessController { return infoList; } + private List<HivePrivilegeInfo> showPriviliegesForObject(HivePrivilegeObject privObj) + throws HiveAuthzPluginException, HiveAccessControlException { + List<HivePrivilegeInfo> infoList = new ArrayList<HivePrivilegeInfo>(); + + if (privObj == null) { + String msg = + SentryHiveConstants.SHOW_NOT_SUPPORTED_FOR_PRINCIPAL + "unspecified object name"; + throw new HiveAuthzPluginException(msg); + } + + try { + sentryClient = getSentryClient(); + Set<List<? extends Authorizable>> authorizableSet = + Sets.newHashSet(SentryAuthorizerUtil.getAuthzHierarchy(new Server(serverName), privObj)); + + Set<String> users = Collections.singleton(authenticator.getUserName()); + SentryObjectPrivileges sentryObjectPrivileges = null; + if (authorizableSet != null && !authorizableSet.isEmpty()) { + hiveAuthzBinding = new HiveAuthzBinding(hiveHook, this.conf, authzConf); + sentryObjectPrivileges = sentryClient + .getAllPrivilegsbyAuthorizable(authenticator.getUserName(), authorizableSet, null, users, hiveAuthzBinding.getActiveRoleSet()); + } else { + String msg = + SentryHiveConstants.SHOW_NOT_SUPPORTED_FOR_PRINCIPAL + "object name [" + privObj.getObjectName() + "] does not exist"; + throw new HiveAuthzPluginException(msg); + } + + Map<TSentryAuthorizable, TSentryPrivilegeMap> rolePrivilegesMap = sentryObjectPrivileges.getPrivilegesForRoles(); + generateHivePrincipalInfo(infoList, rolePrivilegesMap, HivePrincipalType.ROLE); + Map<TSentryAuthorizable, TSentryPrivilegeMap> userPrivilegesMap = sentryObjectPrivileges.getPrivilegesForUsers(); + generateHivePrincipalInfo(infoList, userPrivilegesMap, HivePrincipalType.USER); + + } catch (SentryAccessDeniedException e) { + HiveOperation hiveOp = HiveOperation.SHOW_GRANT; + executeOnFailureHooks(hiveOp, e); + } catch (SentryUserException e) { + String msg = "Error when sentryClient listPrivilegsbyAuthorizable: " + e; + executeOnErrorHooks(msg, e); + } catch (Exception e) { + String msg = "Error when sentryClient listPrivilegsbyAuthorizable: " + e; + executeOnErrorHooks(msg, e); + } finally { + closeClient(); + } + return infoList; + } + + private void generateHivePrincipalInfo(List<HivePrivilegeInfo> infoList, + Map<TSentryAuthorizable, TSentryPrivilegeMap> privilegesMap, + HivePrincipalType principalType) { + if (privilegesMap != null && !privilegesMap.isEmpty()) { + for (TSentryPrivilegeMap map : privilegesMap.values()) { + Map<String, Set<TSentryPrivilege>> principalNameToPrivilegeMap = map.getPrivilegeMap(); + for (String principalName : principalNameToPrivilegeMap.keySet()) { + for (TSentryPrivilege priv : principalNameToPrivilegeMap.get(principalName)) { + infoList.add(SentryAuthorizerUtil + .convert2HivePrivilegeInfo(priv, new HivePrincipal(principalName, + principalType)));//For now only roles are retrieved + } + } + } + } + } + @Override public void setCurrentRole(String roleName) throws HiveAccessControlException, HiveAuthzPluginException { http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestSentryHiveAuthorizationTaskFactory.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestSentryHiveAuthorizationTaskFactory.java b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestSentryHiveAuthorizationTaskFactory.java index 2e3fd7f..8b6b223 100644 --- a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestSentryHiveAuthorizationTaskFactory.java +++ b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestSentryHiveAuthorizationTaskFactory.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.HashMap; import java.util.List; +import org.apache.commons.lang.StringUtils; import org.apache.hadoop.hive.ql.QueryState; import org.junit.Assert; @@ -472,6 +473,51 @@ public class TestSentryHiveAuthorizationTaskFactory { Assert.assertEquals(SERVER, privilegeDesc.getObject()); } + + /** + * SHOW GRANT ... ON SERVER ... + */ + @Test + public void testShowGrantOnServer() throws Exception { + DDLWork work = analyze(parse("SHOW GRANT ON SERVER " + SERVER)); + ShowGrantDesc grantDesc = work.getShowGrantDesc(); + Assert.assertNotNull("Show grant should not be null", grantDesc); + Assert.assertEquals(null, grantDesc.getPrincipalDesc().getType()); + Assert.assertEquals(StringUtils.EMPTY, grantDesc.getPrincipalDesc().getName()); + Assert.assertEquals(SERVER, grantDesc.getHiveObj().getObject()); + Assert.assertTrue("Expected server", ((SentryHivePrivilegeObjectDesc)grantDesc.getHiveObj()).getServer()); + } + + /** + * SHOW GRANT ... ON DATABASE ... + */ + @Test + public void testShowGrantOnDatabase() throws Exception { + DDLWork work = analyze(parse("SHOW GRANT ON DATABASE " + DB)); + ShowGrantDesc grantDesc = work.getShowGrantDesc(); + Assert.assertNotNull("Show grant should not be null", grantDesc); + Assert.assertEquals(null, grantDesc.getPrincipalDesc().getType()); + Assert.assertEquals(StringUtils.EMPTY, grantDesc.getPrincipalDesc().getName()); + Assert.assertEquals(DB, grantDesc.getHiveObj().getObject()); + //TODO - Part of SENTRY-2238 commit +// Assert.assertTrue("Expected database", ((SentryHivePrivilegeObjectDesc)grantDesc.getHiveObj()).getDatabase()); + } + + /** + * SHOW GRANT ... ON TABLE ... + */ + @Test + public void testShowGrantOnTable() throws Exception { + DDLWork work = analyze(parse("SHOW GRANT ON TABLE " + TABLE)); + ShowGrantDesc grantDesc = work.getShowGrantDesc(); + Assert.assertNotNull("Show grant should not be null", grantDesc); + Assert.assertEquals(null, grantDesc.getPrincipalDesc().getType()); + Assert.assertEquals(StringUtils.EMPTY, grantDesc.getPrincipalDesc().getName()); + Assert.assertEquals(TABLE, grantDesc.getHiveObj().getObject()); + Assert.assertTrue("Expected table", ((SentryHivePrivilegeObjectDesc)grantDesc.getHiveObj()).getTable()); + } + + /* Db prefix in grant */ http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryObjectPrivileges.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryObjectPrivileges.java b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryObjectPrivileges.java new file mode 100644 index 0000000..631857c --- /dev/null +++ b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryObjectPrivileges.java @@ -0,0 +1,54 @@ +/** + * 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.sentry.api.service.thrift; + +import java.util.Map; + +/** + * Wrapper around TListSentryPrivilegesByAuthResponse. + * <p> + * Allows getting all the results associated with the response + * in a single fetch + */ +public class SentryObjectPrivileges { + + private Map<TSentryAuthorizable, TSentryPrivilegeMap> privilegesForRoles; + private Map<TSentryAuthorizable, TSentryPrivilegeMap> privilegesForUsers; + + SentryObjectPrivileges(TListSentryPrivilegesByAuthResponse response) { + + privilegesForRoles = response.getPrivilegesMapByAuth(); + privilegesForUsers = response.getPrivilegesMapByAuthForUsers(); + } + + /** + * Return a map of authorizable to a mapping of roleNames to TSentryPrivileges + * @return + */ + public Map<TSentryAuthorizable, TSentryPrivilegeMap> getPrivilegesForRoles() { + return privilegesForRoles; + } + + /** + * Return a map of authorizable to a mapping of userNames to TSentryPrivileges + * @return + */ + public Map<TSentryAuthorizable, TSentryPrivilegeMap> getPrivilegesForUsers() { + return privilegesForUsers; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClient.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClient.java b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClient.java index 6f38ed2..3950ea5 100644 --- a/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClient.java +++ b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClient.java @@ -243,6 +243,28 @@ public interface SentryPolicyServiceClient extends AutoCloseable { Set<String> groups, Set<String> users, ActiveRoleSet roleSet) throws SentryUserException; /** + * Returns an encapsulation of objects for all types assigned to a set of users and/or groups available in a + * set of authorizable objects. + * + * @param requestorUserName The user who is requesting the list of privileges. + * @param authorizables A list of authorizable objects to look for privileges. + * If null, then privileges of any authorizable object should be returned. + * @param groups A list of groups to look for privileges assigned. + * If null, then privileges of any group on the specified authorizable object + * should be returned. + * @param users A list of users to look for privileges assigned. + * If null, then privileges of any user on the specified authorizable object + * should be returned. + * @param roleSet The active role the group and/or user has. If null, then privileges of + * any role on the specified group or user should be returned. + * @return A an instance of SentryObjectPrivileges on the specified authorizable object. + * @throws SentryUserException In case an error occurs while getting the list of privileges. + */ + SentryObjectPrivileges getAllPrivilegsbyAuthorizable( + String requestorUserName, Set<List<? extends Authorizable>> authorizables, + Set<String> groups, Set<String> users, ActiveRoleSet roleSet) throws SentryUserException; + + /** * Returns the configuration value in the sentry server associated with propertyName, or if * propertyName does not exist, the defaultValue. There is no "requestorUserName" because this is * regarded as an internal interface. http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClientDefaultImpl.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClientDefaultImpl.java b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClientDefaultImpl.java index 45dce0e..28d345e 100644 --- a/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClientDefaultImpl.java +++ b/sentry-service/sentry-service-api/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyServiceClientDefaultImpl.java @@ -939,14 +939,37 @@ public class SentryPolicyServiceClientDefaultImpl implements SentryPolicyService String requestorUserName, Set<List<? extends Authorizable>> authorizables, Set<String> groups, Set<String> users, ActiveRoleSet roleSet) throws SentryUserException { + + TListSentryPrivilegesByAuthResponse response = + getSentryPrivilegeByAuthResponse(requestorUserName, authorizables, groups, users, roleSet); + + return response.getPrivilegesMapByAuth(); + } + + @Override + public SentryObjectPrivileges getAllPrivilegsbyAuthorizable + ( + String requestorUserName, + Set<List<? extends Authorizable>> authorizables, Set<String> groups, + Set<String> users, ActiveRoleSet roleSet) throws SentryUserException { + + TListSentryPrivilegesByAuthResponse response = + getSentryPrivilegeByAuthResponse(requestorUserName, authorizables, groups, users, roleSet); + + return new SentryObjectPrivileges(response); + } + + public TListSentryPrivilegesByAuthResponse getSentryPrivilegeByAuthResponse(String requestorUserName, + Set<List<? extends Authorizable>> authorizables, Set<String> groups, Set<String> users, + ActiveRoleSet roleSet) throws SentryUserException { Set<TSentryAuthorizable> authSet = Sets.newTreeSet(); for (List<? extends Authorizable> authorizableHierarchy : authorizables) { authSet.add(setupSentryAuthorizable(authorizableHierarchy)); } TListSentryPrivilegesByAuthRequest request = new TListSentryPrivilegesByAuthRequest( - ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT, requestorUserName, - authSet); + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT, requestorUserName, + authSet); if (groups != null) { request.setGroups(groups); } @@ -961,7 +984,11 @@ public class SentryPolicyServiceClientDefaultImpl implements SentryPolicyService TListSentryPrivilegesByAuthResponse response = client .list_sentry_privileges_by_authorizable(request); Status.throwIfNotOk(response.getStatus()); - return response.getPrivilegesMapByAuth(); + + if(response == null) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE + ": received a NULL response while requesting for sentry privileges by authorizable"); + } + return response; } catch (TException e) { throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); } http://git-wip-us.apache.org/repos/asf/sentry/blob/bee44c28/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestShowGrants.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestShowGrants.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestShowGrants.java new file mode 100644 index 0000000..500b38b --- /dev/null +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestShowGrants.java @@ -0,0 +1,227 @@ +/* + * 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.sentry.tests.e2e.dbprovider; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.Assert; + +import org.apache.sentry.binding.hive.conf.HiveAuthzConf; +import org.apache.sentry.tests.e2e.hive.AbstractTestWithStaticConfiguration; +import org.apache.sentry.tests.e2e.hive.DummySentryOnFailureHook; +import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestShowGrants extends AbstractTestWithStaticConfiguration { + + private static int SHOW_GRANT_DB_POSITION = 1; + private static int SHOW_GRANT_TABLE_POSITION = 2; + + @BeforeClass + public static void setupTestStaticConfiguration() throws Exception { + useSentryService = true; + String hiveServer2Type = System + .getProperty(HiveServerFactory.HIVESERVER2_TYPE); + if ((hiveServer2Type == null) + || HiveServerFactory.isInternalServer(HiveServerFactory.HiveServer2Type + .valueOf(hiveServer2Type.trim()))) { + System.setProperty( + HiveAuthzConf.AuthzConfVars.AUTHZ_ONFAILURE_HOOKS.getVar(), + DummySentryOnFailureHook.class.getName()); + } + AbstractTestWithStaticConfiguration.setupTestStaticConfiguration(); + } + + @Override + @Before + public void setup() throws Exception { + DummySentryOnFailureHook.invoked = false; + super.setupAdmin(); + super.setup(); + setupTestCase(); + } + + private void setupTestCase() throws Exception { + // setup db objects needed by the test + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + + statement.execute("DROP DATABASE IF EXISTS db_1 CASCADE"); + statement.execute("CREATE DATABASE db_1"); + statement.execute("CREATE DATABASE db_2"); + statement.execute("USE db_1"); + statement.execute("CREATE TABLE foo (id int)"); + statement.execute("USE db_2"); + statement.execute("CREATE TABLE bar (id int)"); + + statement.execute("CREATE ROLE role1"); + statement.execute("CREATE ROLE role2"); + statement.execute("CREATE ROLE role3"); + statement.execute("CREATE ROLE role4"); + + statement.execute("GRANT ROLE role1 TO GROUP " + USERGROUP1); + statement.execute("GRANT ROLE role1 TO GROUP " + USERGROUP2); + statement.execute("GRANT ROLE role2 TO GROUP " + USERGROUP2); + statement.execute("GRANT ROLE role3 TO GROUP " + USERGROUP2); + statement.execute("GRANT ROLE role4 TO GROUP " + USERGROUP3); + statement.execute("GRANT ROLE role4 TO GROUP " + USERGROUP4); + + //Grant on server to role 1 + statement.execute("GRANT ALL ON SERVER server1 TO ROLE role1"); + + // Grant select on database db_1 to role2 + // Grant insert on database db_1 to role3 + // Grant all on database db_2 to role3 + statement.execute("GRANT SELECT ON DATABASE db_1 TO ROLE role2"); + statement.execute("GRANT INSERT ON DATABASE db_1 TO ROLE role3"); + statement.execute("GRANT ALL ON DATABASE db_2 TO ROLE role4"); + + // Grant select on table db_2.bar to role role2 + // Grant insert on table db_2.bar to role role3 + // Grant all on table db_1.foo to role role4 + statement.execute("GRANT ALL ON TABLE db_1.foo TO ROLE role4"); + statement.execute("GRANT ALL ON TABLE db_1.foo TO ROLE role3"); + statement.execute("GRANT SELECT ON TABLE db_2.bar TO ROLE role2"); + statement.execute("GRANT INSERT ON TABLE db_2.bar TO ROLE role3"); + + //Grant all on uri '/a/b/c' to role1 + //Grant all on uri '/x/y/z' to role2, role3, role4 + statement.execute("GRANT ALL ON URI \"file:///a/b/c\" TO ROLE role1"); + statement.execute("GRANT ALL ON URI \"file:///x/y/z\" TO ROLE role3"); + statement.execute("GRANT ALL ON URI \"file:///x/y/z\" TO ROLE role4"); + + statement.close(); + connection.close(); + } + + /** + * Test show grants on objects for admin users + * @throws Exception + */ + @Test + public void testShowGrantsOnObjectsForAdmin() throws Exception { + // setup db objects needed by the test + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + + ResultSet resultSet = null; + resultSet = statement.executeQuery("SHOW GRANT ON SERVER server1"); + assertResultSize(resultSet, 2);//Role1 + Admin + Assert.assertEquals("*", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_1"); + assertResultSize(resultSet, 2); + Assert.assertEquals("db_1", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_2"); + assertResultSize(resultSet, 1); + Assert.assertEquals("db_2", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON TABLE db_1.foo"); + assertResultSize(resultSet, 2); + Assert.assertEquals("foo", resultSet.getString(SHOW_GRANT_TABLE_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON TABLE db_2.bar"); + assertResultSize(resultSet, 2); + Assert.assertEquals("bar", resultSet.getString(SHOW_GRANT_TABLE_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON URI \"file:///a/b/c\""); + assertResultSize(resultSet, 1); + Assert.assertEquals("file:///a/b/c", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON URI \"file:///x/y/z\""); + assertResultSize(resultSet, 2); + Assert.assertEquals("file:///x/y/z", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + statement.close(); + connection.close(); + } + + /** + * Test show grants on objects for non-admin users + * @throws Exception + */ + @Test + public void testShowGrantsOnObjectsForNonAdmins() throws Exception { + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + + ResultSet resultSet = null; + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_1"); + assertResultSize(resultSet, 0); + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_2"); + assertResultSize(resultSet, 0); + + statement.close(); + connection.close(); + + // setup db objects needed by the test + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_1"); + assertResultSize(resultSet, 2); + Assert.assertEquals("db_1", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON DATABASE db_2"); + assertResultSize(resultSet, 0); + + resultSet = statement.executeQuery("SHOW GRANT ON TABLE db_1.foo"); + assertResultSize(resultSet, 2); + + statement.close(); + connection.close(); + + // setup db objects needed by the test + connection = context.createConnection(USER4_1); + statement = context.createStatement(connection); + + resultSet = statement.executeQuery("SHOW GRANT ON TABLE db_1.foo"); + assertResultSize(resultSet, 2); + Assert.assertEquals("foo", resultSet.getString(SHOW_GRANT_TABLE_POSITION)); + + resultSet = statement.executeQuery("SHOW GRANT ON TABLE db_2.bar"); + assertResultSize(resultSet, 0); + + resultSet = statement.executeQuery("SHOW GRANT ON URI \"file:///a/b/c\""); + assertResultSize(resultSet, 0); + + resultSet = statement.executeQuery("SHOW GRANT ON URI \"file:///x/y/z\""); + assertResultSize(resultSet, 2); + Assert.assertEquals("file:///x/y/z", resultSet.getString(SHOW_GRANT_DB_POSITION)); + + statement.close(); + connection.close(); + } + + private void assertResultSize(ResultSet resultSet, int expected) throws SQLException{ + int count = 0; + while(resultSet.next()) { + count++; + } + Assert.assertEquals(count, expected); + } + +}
