Repository: incubator-sentry Updated Branches: refs/heads/master 56802bba0 -> 382a93318
SENTRY-494: UNLOCK TABLE is not allowed (Reviewed by:Prasad Mujumdar) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/382a9331 Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/382a9331 Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/382a9331 Branch: refs/heads/master Commit: 382a93318fa78ceb0d43c0991af467710e8fe68b Parents: 56802bb Author: Ma Junjie <[email protected]> Authored: Wed Jan 21 15:38:22 2015 +0800 Committer: Ma Junjie <[email protected]> Committed: Wed Jan 21 15:38:22 2015 +0800 ---------------------------------------------------------------------- .../binding/hive/HiveAuthzBindingHook.java | 3 +- .../hive/authz/HiveAuthzPrivilegesMap.java | 16 +- .../AbstractTestWithStaticConfiguration.java | 12 +- .../tests/e2e/hive/TestLockPrivileges.java | 214 +++++++++++++++++++ 4 files changed, 237 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/382a9331/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java index 862c6a5..e311398 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java @@ -162,6 +162,8 @@ public class HiveAuthzBindingHook extends AbstractSemanticAnalyzerHook { case HiveParser.TOK_ALTERVIEW_RENAME: case HiveParser.TOK_CREATEINDEX: case HiveParser.TOK_DROPINDEX: + case HiveParser.TOK_LOCKTABLE: + case HiveParser.TOK_UNLOCKTABLE: currTab = extractTable((ASTNode)ast.getFirstChildWithType(HiveParser.TOK_TABNAME)); currDB = extractDatabase((ASTNode) ast.getChild(0)); break; @@ -430,7 +432,6 @@ public class HiveAuthzBindingHook extends AbstractSemanticAnalyzerHook { } getInputHierarchyFromInputs(inputHierarchy, inputs); - for (WriteEntity writeEntity: outputs) { if (filterWriteEntity(writeEntity)) { continue; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/382a9331/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java index 11c1a0f..99f1eb0 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import org.apache.hadoop.hive.ql.plan.HiveOperation; -import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveExtendedOperation; import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveOperationScope; import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveOperationType; import org.apache.sentry.core.model.db.DBModelAction; @@ -161,12 +160,17 @@ public class HiveAuthzPrivilegesMap { setOperationType(HiveOperationType.INFO). build(); - HiveAuthzPrivileges tableDMLPrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder(). - addOutputObjectPriviledge(AuthorizableType.Table, EnumSet.of(DBModelAction.INSERT)). + HiveAuthzPrivileges tableLockPrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge(AuthorizableType.Table, EnumSet.of(DBModelAction.LOCK)). setOperationScope(HiveOperationScope.TABLE). setOperationType(HiveOperationType.DML). build(); + HiveAuthzPrivileges dbLockPrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge(AuthorizableType.Db, EnumSet.of(DBModelAction.LOCK)) + .setOperationScope(HiveOperationScope.DATABASE).setOperationType(HiveOperationType.DML) + .build(); + HiveAuthzPrivileges functionPrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder(). addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.ALL)). addOutputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.ALL)). @@ -257,8 +261,10 @@ public class HiveAuthzPrivilegesMap { hiveAuthzStmtPrivMap.put(HiveOperation.EXPORT, tableExportPrivilege); hiveAuthzStmtPrivMap.put(HiveOperation.IMPORT, dbImportPrivilege); hiveAuthzStmtPrivMap.put(HiveOperation.LOAD, tableLoadPrivilege); - hiveAuthzStmtPrivMap.put(HiveOperation.LOCKTABLE, tableDMLPrivilege);//TODO: Needs test case - hiveAuthzStmtPrivMap.put(HiveOperation.UNLOCKTABLE, tableDMLPrivilege);//TODO: Needs test case + hiveAuthzStmtPrivMap.put(HiveOperation.LOCKTABLE, tableLockPrivilege); + hiveAuthzStmtPrivMap.put(HiveOperation.UNLOCKTABLE, tableLockPrivilege); + hiveAuthzStmtPrivMap.put(HiveOperation.LOCKDB, dbLockPrivilege); + hiveAuthzStmtPrivMap.put(HiveOperation.UNLOCKDB, dbLockPrivilege); // CREATEROLE // DROPROLE // GRANT_PRIVILEGE http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/382a9331/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java index f8cc1d0..689f5a6 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java @@ -19,6 +19,7 @@ package org.apache.sentry.tests.e2e.hive; import static org.apache.sentry.provider.common.ProviderConstants.AUTHORIZABLE_SPLITTER; import static org.apache.sentry.provider.common.ProviderConstants.PRIVILEGE_PREFIX; import static org.apache.sentry.provider.common.ProviderConstants.ROLE_SPLITTER; +import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; @@ -60,7 +61,6 @@ import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory; import org.apache.tools.ant.util.StringUtils; import org.junit.After; import org.junit.AfterClass; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.BeforeClass; import org.slf4j.Logger; @@ -113,7 +113,7 @@ public abstract class AbstractTestWithStaticConfiguration { protected static boolean useSentryService = false; protected static boolean setMetastoreListener = false; protected static String testServerType = null; - + protected static boolean enableHiveConcurrency = false; protected static File baseDir; protected static File logDir; @@ -224,6 +224,14 @@ public abstract class AbstractTestWithStaticConfiguration { setupSentryService(); } + if (enableHiveConcurrency) { + properties.put(HiveConf.ConfVars.HIVE_SUPPORT_CONCURRENCY.varname, "true"); + properties.put(HiveConf.ConfVars.HIVE_TXN_MANAGER.varname, + "org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager"); + properties.put(HiveConf.ConfVars.HIVE_LOCK_MANAGER.varname, + "org.apache.hadoop.hive.ql.lockmgr.EmbeddedLockManager"); + } + hiveServer = create(properties, baseDir, confDir, logDir, policyURI, fileSystem); hiveServer.start(); createContext(); http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/382a9331/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java new file mode 100644 index 0000000..0e403d8 --- /dev/null +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java @@ -0,0 +1,214 @@ +/** + * 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.hive; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + +import org.apache.sentry.provider.file.PolicyFile; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestLockPrivileges extends AbstractTestWithStaticConfiguration { + private PolicyFile policyFile; + final String tableName = "tb1"; + + static Map<String, String> privileges = new HashMap<String, String>(); + static { + privileges.put("all_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=all"); + privileges.put("select_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=select"); + privileges.put("insert_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=insert"); + privileges.put("alter_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=alter"); + privileges.put("lock_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=lock"); + + privileges.put("all_db1", "server=server1->db=" + DB1 + "->action=all"); + privileges.put("select_db1", "server=server1->db=" + DB1 + "->action=select"); + privileges.put("insert_db1", "server=server1->db=" + DB1 + "->action=insert"); + privileges.put("alter_db1", "server=server1->db=" + DB1 + "->action=alter"); + privileges.put("lock_db1", "server=server1->db=" + DB1 + "->action=lock"); + } + + @BeforeClass + public static void setHiveConcurrency() throws Exception { + enableHiveConcurrency = true; + setupTestStaticConfiguration(); + } + + private void adminCreate(String db, String table) throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("DROP DATABASE IF EXISTS " + db + " CASCADE"); + statement.execute("CREATE DATABASE " + db); + if (table != null) { + statement.execute("CREATE table " + db + "." + table + " (a string)"); + } + statement.close(); + connection.close(); + } + + @Before + public void setup() throws Exception { + policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP).setUserGroupMapping( + StaticUserGroup.getStaticMapping()); + writePolicyFile(policyFile); + } + + @Test + public void testLockDatabase() throws Exception { + String partialErrorMsgForNoPrivilege = "No valid privileges"; + String assertErrorException = "The exception is not the same as the expectation."; + String assertExceptionThrown = "SQLException will be thrown."; + + adminCreate(DB1, null); + policyFile.addPermissionsToRole("lock_db1", privileges.get("lock_db1")) + .addRolesToGroup(USERGROUP1, "lock_db1") + .addPermissionsToRole("insert_db1", privileges.get("insert_db1")) + .addRolesToGroup(USERGROUP2, "insert_db1") + .addPermissionsToRole("select_db1", privileges.get("select_db1")) + .addRolesToGroup(USERGROUP2, "select_db1") + .addPermissionsToRole("alter_db1", privileges.get("alter_db1")) + .addRolesToGroup(USERGROUP2, "alter_db1") + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addRolesToGroup(USERGROUP3, "all_db1"); + writePolicyFile(policyFile); + + // user1 has lock privilege only + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("LOCK DATABASE db_1 SHARED"); + try { + statement.execute("UNLOCK DATABASE db_1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is successful. + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1); + } + + // user2 has privileges with insert, select, alter, but has no lock privilege + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + try { + statement.execute("LOCK DATABASE db_1 SHARED"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is failed, the error message include "No valid privileges" + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0); + } + try { + statement.execute("UNLOCK DATABASE db_1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is failed, the error message include "No valid privileges" + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0); + } + + // user3 has All privilege + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("LOCK DATABASE db_1 SHARED"); + try { + statement.execute("UNLOCK DATABASE db_1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is successful. + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1); + } + statement.close(); + connection.close(); + } + + @Test + public void testLockTable() throws Exception { + String partialErrorMsgForNoPrivilege = "No valid privileges"; + String assertErrorException = "The exception is not the same as the expectation."; + String assertExceptionThrown = "SQLException will be thrown."; + + adminCreate(DB1, tableName); + policyFile.addPermissionsToRole("lock_db1_tb1", privileges.get("lock_db1_tb1")) + .addRolesToGroup(USERGROUP1, "lock_db1_tb1") + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP2, "insert_db1_tb1") + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addRolesToGroup(USERGROUP2, "select_db1_tb1") + .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1")) + .addRolesToGroup(USERGROUP2, "alter_db1_tb1") + .addPermissionsToRole("all_db1_tb1", privileges.get("all_db1_tb1")) + .addRolesToGroup(USERGROUP3, "all_db1_tb1"); + writePolicyFile(policyFile); + + // user1 has lock privilege only + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("LOCK TABLE tb1 SHARED"); + try { + statement.execute("UNLOCK TABLE tb1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is successful. + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1); + } + + // user2 has privileges with insert, select, alter, but has no lock privilege + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + try { + statement.execute("LOCK TABLE tb1 SHARED"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is failed, the error message include "No valid privileges" + assertTrue(assertErrorException, + se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0); + } + try { + statement.execute("UNLOCK TABLE tb1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is failed, the error message include "No valid privileges" + assertTrue(assertErrorException, + se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0); + } + + // user3 has All privilege + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("LOCK TABLE tb1 SHARED"); + try { + statement.execute("UNLOCK TABLE tb1"); + fail(assertExceptionThrown); + } catch (SQLException se) { + // Authorization is successful. + assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1); + } + statement.close(); + connection.close(); + } +}
