You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by li...@apache.org on 2018/07/06 16:24:12 UTC
sentry git commit: SENTRY-2247: Add e2e tests to verify owner
privileges (Na Li, reviewed by Sergio Pena, Kalyan Kumar Kalvagadda,
Arjun Mishra)
Repository: sentry
Updated Branches:
refs/heads/master 702495b40 -> dbf83ab2b
SENTRY-2247: Add e2e tests to verify owner privileges (Na Li, reviewed by Sergio Pena, Kalyan Kumar Kalvagadda, Arjun Mishra)
Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/dbf83ab2
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/dbf83ab2
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/dbf83ab2
Branch: refs/heads/master
Commit: dbf83ab2b31219b9d3d1e94265917ae1a292cc69
Parents: 702495b
Author: lina.li <li...@cloudera.com>
Authored: Fri Jul 6 11:22:33 2018 -0500
Committer: lina.li <li...@cloudera.com>
Committed: Fri Jul 6 11:22:33 2018 -0500
----------------------------------------------------------------------
.../thrift/SentryPolicyStoreProcessor.java | 1 +
.../db/service/persistent/SentryStore.java | 125 +++--
.../thrift/TestSentryPolicyStoreProcessor.java | 11 +-
.../e2e/dbprovider/TestOwnerPrivileges.java | 469 +++++++++++++++++++
.../TestOwnerPrivilegesWithGrantOption.java | 30 ++
.../tests/e2e/hdfs/TestHDFSIntegrationBase.java | 12 +-
6 files changed, 575 insertions(+), 73 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
index 98f2e29..2efc8cf 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
@@ -1647,6 +1647,7 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
ServerConfig.SENTRY_OWNER_PRIVILEGE_WITH_GRANT_DEFAULT);
TSentryPrivilege ownerPrivilege = new TSentryPrivilege();
+ ownerPrivilege.setServerName(authorizable.getServer());
ownerPrivilege.setDbName(authorizable.getDb());
if(!Strings.isNullOrEmpty(authorizable.getTable())) {
ownerPrivilege.setTableName(authorizable.getTable());
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index ff0b4c0..4f7bdbd 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -155,7 +155,7 @@ public class SentryStore implements SentryStoreInterface {
AccessConstants.ALL, AccessConstants.ACTION_ALL,
AccessConstants.SELECT, AccessConstants.INSERT, AccessConstants.ALTER,
AccessConstants.CREATE, AccessConstants.DROP, AccessConstants.INDEX,
- AccessConstants.LOCK);
+ AccessConstants.LOCK, AccessConstants.OWNER);
// Now partial revoke just support action with SELECT,INSERT and ALL.
// Now partial revoke just support action with SELECT,INSERT, and ALL.
@@ -1258,7 +1258,7 @@ public class SentryStore implements SentryStoreInterface {
// otherwise,
// we will revoke it from role directly
MSentryPrivilege persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(mPrivilege), pm);
- if (persistedPriv != null && !persistedPriv.getRoles().isEmpty()) {
+ if (persistedPriv != null) {
persistedPriv.removeEntity(mEntity);
persistPrivilege(pm, persistedPriv);
}
@@ -2619,22 +2619,8 @@ public class SentryStore implements SentryStoreInterface {
pm -> {
pm.setDetachAllOnCommit(false); // No need to detach objects
- // Drop the give privilege for all possible actions from all entities.
- TSentryPrivilege tPrivilege = toSentryPrivilege(tAuthorizable);
+ dropPrivilegeCore(pm, tAuthorizable);
- try {
- if (isMultiActionsSupported(tPrivilege)) {
- for (String privilegeAction : ALL_ACTIONS) {
- tPrivilege.setAction(privilegeAction);
- dropPrivilegeForAllEntities(pm, new TSentryPrivilege(tPrivilege));
- }
- } else {
- dropPrivilegeForAllEntities(pm, new TSentryPrivilege(tPrivilege));
- }
- } catch (JDODataStoreException e) {
- throw new SentryInvalidInputException("Failed to get privileges: "
- + e.getMessage());
- }
return null;
});
}
@@ -2652,24 +2638,31 @@ public class SentryStore implements SentryStoreInterface {
execute(update, pm -> {
pm.setDetachAllOnCommit(false); // No need to detach objects
- // Drop the give privilege for all possible actions from all entities.
- TSentryPrivilege tPrivilege = toSentryPrivilege(tAuthorizable);
+ dropPrivilegeCore(pm, tAuthorizable);
- try {
- if (isMultiActionsSupported(tPrivilege)) {
- for (String privilegeAction : ALL_ACTIONS) {
- tPrivilege.setAction(privilegeAction);
- dropPrivilegeForAllEntities(pm, new TSentryPrivilege(tPrivilege));
- }
- } else {
+ return null;
+ });
+ }
+
+ private void dropPrivilegeCore(PersistenceManager pm, TSentryAuthorizable tAuthorizable) throws Exception {
+
+ // Drop the give privilege for all possible actions from all entities.
+ TSentryPrivilege tPrivilege = toSentryPrivilege(tAuthorizable);
+ tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+
+ try {
+ if (isMultiActionsSupported(tPrivilege)) {
+ for (String privilegeAction : ALL_ACTIONS) {
+ tPrivilege.setAction(privilegeAction);
dropPrivilegeForAllEntities(pm, new TSentryPrivilege(tPrivilege));
}
- } catch (JDODataStoreException e) {
- throw new SentryInvalidInputException("Failed to get privileges: "
- + e.getMessage());
+ } else {
+ dropPrivilegeForAllEntities(pm, new TSentryPrivilege(tPrivilege));
}
- return null;
- });
+ } catch (JDODataStoreException e) {
+ throw new SentryInvalidInputException("Failed to get privileges: "
+ + e.getMessage());
+ }
}
/**
@@ -2757,25 +2750,7 @@ public class SentryStore implements SentryStoreInterface {
pm -> {
pm.setDetachAllOnCommit(false); // No need to detach objects
- // Drop the give privilege for all possible actions from all entities.
- TSentryPrivilege tPrivilege = toSentryPrivilege(oldTAuthorizable);
- TSentryPrivilege newPrivilege = toSentryPrivilege(newTAuthorizable);
-
- try {
- // In case of tables or DBs, check all actions
- if (isMultiActionsSupported(tPrivilege)) {
- for (String privilegeAction : ALL_ACTIONS) {
- tPrivilege.setAction(privilegeAction);
- newPrivilege.setAction(privilegeAction);
- renamePrivilegeForAllEntities(pm, tPrivilege, newPrivilege);
- }
- } else {
- renamePrivilegeForAllEntities(pm, tPrivilege, newPrivilege);
- }
- } catch (JDODataStoreException e) {
- throw new SentryInvalidInputException("Failed to get privileges: "
- + e.getMessage());
- }
+ renamePrivilegeCore(pm, oldTAuthorizable, newTAuthorizable);
return null;
});
}
@@ -2798,27 +2773,43 @@ public class SentryStore implements SentryStoreInterface {
execute(update, pm -> {
pm.setDetachAllOnCommit(false); // No need to detach objects
- // Drop the give privilege for all possible actions from all entities.
- TSentryPrivilege tPrivilege = toSentryPrivilege(oldTAuthorizable);
- TSentryPrivilege newPrivilege = toSentryPrivilege(newTAuthorizable);
+ renamePrivilegeCore(pm, oldTAuthorizable, newTAuthorizable);
+ return null;
+ });
+ }
- try {
- // In case of tables or DBs, check all actions
- if (isMultiActionsSupported(tPrivilege)) {
- for (String privilegeAction : ALL_ACTIONS) {
- tPrivilege.setAction(privilegeAction);
- newPrivilege.setAction(privilegeAction);
- renamePrivilegeForAllEntities(pm, tPrivilege, newPrivilege);
- }
- } else {
+ private void renamePrivilegeCore(PersistenceManager pm, TSentryAuthorizable oldTAuthorizable,
+ final TSentryAuthorizable newTAuthorizable) throws Exception {
+ TSentryPrivilege tPrivilege = toSentryPrivilege(oldTAuthorizable);
+ TSentryPrivilege newPrivilege = toSentryPrivilege(newTAuthorizable);
+
+ tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+ newPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+ renamePrivilegeCore(pm, tPrivilege, newPrivilege);
+
+ tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+ newPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+ renamePrivilegeCore(pm, tPrivilege, newPrivilege);
+ }
+
+ private void renamePrivilegeCore(PersistenceManager pm, TSentryPrivilege tPrivilege,
+ final TSentryPrivilege newPrivilege) throws Exception {
+
+ try {
+ // In case of tables or DBs, check all actions
+ if (isMultiActionsSupported(tPrivilege)) {
+ for (String privilegeAction : ALL_ACTIONS) {
+ tPrivilege.setAction(privilegeAction);
+ newPrivilege.setAction(privilegeAction);
renamePrivilegeForAllEntities(pm, tPrivilege, newPrivilege);
}
- } catch (JDODataStoreException e) {
- throw new SentryInvalidInputException("Failed to get privileges: "
- + e.getMessage());
+ } else {
+ renamePrivilegeForAllEntities(pm, tPrivilege, newPrivilege);
}
- return null;
- });
+ } catch (JDODataStoreException e) {
+ throw new SentryInvalidInputException("Failed to get privileges: "
+ + e.getMessage());
+ }
}
// Currently INSERT/SELECT/ALL are supported for Table and DB level privileges
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
index 14a0fd8..3475624 100644
--- a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
@@ -199,7 +199,7 @@ public class TestSentryPolicyStoreProcessor {
new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
conf, sentryStore);
TSentryPrivilege privilege = new TSentryPrivilege();
- TSentryAuthorizable authorizable = new TSentryAuthorizable("");
+ TSentryAuthorizable authorizable = new TSentryAuthorizable("server1");
authorizable.setDb("db1");
authorizable.setTable("tb1");
@@ -212,13 +212,14 @@ public class TestSentryPolicyStoreProcessor {
sentryServiceHandler =
new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
conf, sentryStore);
- authorizable = new TSentryAuthorizable("");
+ authorizable = new TSentryAuthorizable("server1");
authorizable.setTable("tb1");
assertNull(sentryServiceHandler.constructOwnerPrivilege(authorizable));
//Check the behavior when DB name is set and table name is not set.
- authorizable = new TSentryAuthorizable("");
+ authorizable = new TSentryAuthorizable("server1");
authorizable.setDb("db1");
+ privilege.setServerName("server1");
privilege.setDbName("db1");
privilege.setAction(AccessConstants.OWNER);
privilege.setPrivilegeScope("DATABASE");
@@ -226,7 +227,7 @@ public class TestSentryPolicyStoreProcessor {
Assert.assertEquals(privilege, sentryServiceHandler.constructOwnerPrivilege(authorizable));
//check the behaviour when both DB name and table name are set
- authorizable = new TSentryAuthorizable("");
+ authorizable = new TSentryAuthorizable("server1");
authorizable.setDb("db1");
authorizable.setTable("tb1");
privilege.setTableName("tb1");
@@ -240,7 +241,7 @@ public class TestSentryPolicyStoreProcessor {
sentryServiceHandler =
new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
conf, sentryStore);
- authorizable = new TSentryAuthorizable("");
+ authorizable = new TSentryAuthorizable("server1");
authorizable.setDb("db1");
authorizable.setTable("tb1");
privilege.setPrivilegeScope("TABLE");
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivileges.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivileges.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivileges.java
new file mode 100644
index 0000000..8a10214
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivileges.java
@@ -0,0 +1,469 @@
+/**
+ * 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 static org.hamcrest.Matchers.equalToIgnoringCase;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.google.common.collect.Sets;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.sentry.tests.e2e.hdfs.TestHDFSIntegrationBase;
+import org.apache.sentry.tests.e2e.hive.StaticUserGroup;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestOwnerPrivileges extends TestHDFSIntegrationBase {
+
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(TestHDFSIntegrationBase.class);
+ private final static String tableName1 = "tb_1";
+
+ protected static final String ALL_DB1 = "server=server1->db=db_1",
+ ADMIN1 = StaticUserGroup.ADMIN1,
+ ADMINGROUP = StaticUserGroup.ADMINGROUP,
+ USER1_1 = StaticUserGroup.USER1_1,
+ USER1_2 = StaticUserGroup.USER1_2,
+ USERGROUP1 = StaticUserGroup.USERGROUP1,
+ DB1 = "db_1";
+
+ private final static String renameTag = "_new";
+ private Connection connection;
+ private Statement statement;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ ownerPrivilegeEnabled = true;
+
+ TestHDFSIntegrationBase.setup();
+ }
+
+ @Before
+ public void initialize() throws Exception{
+ super.setUpTempDir();
+ admin = "hive";
+ connection = hiveServer2.createConnection(admin, admin);
+ statement = connection.createStatement();
+ statement.execute("create role admin_role");
+ statement.execute("grant role admin_role to group hive");
+ statement.execute("grant all on server server1 to role admin_role");
+ }
+
+ /**
+ * Verify that the user who creases database has owner privilege on this database
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateDatabase() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+
+ // setup privileges for USER1
+ statement.execute("GRANT CREATE ON SERVER server1" + " TO ROLE create_db1");
+
+ // USER1 creates test DB
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE DATABASE " + DB1);
+
+ // verify privileges created for new database
+ verifyTablePrivilegeExistForUser(statementUSER1_1, Lists.newArrayList(USER1_1),
+ DB1, null, 1);
+
+ // verify that user has all privilege on this database, i.e., "OWNER" means "ALL"
+ // for authorization
+ statementUSER1_1.execute("CREATE TABLE " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column')");
+ statementUSER1_1.execute("INSERT INTO TABLE " + DB1 + "." + tableName1 + " VALUES (35)");
+ statementUSER1_1.execute("ALTER TABLE " + DB1 + "." + tableName1 + " RENAME TO " +
+ DB1 + "." + tableName1 + renameTag );
+ statementUSER1_1.execute("DROP TABLE " + DB1 + "." + tableName1 + renameTag);
+ statementUSER1_1.execute("DROP DATABASE " + DB1 + " CASCADE");
+
+ statement.close();
+ connection.close();
+
+ statementUSER1_1.close();
+ connectionUSER1_1.close();
+ }
+
+ /**
+ * Verify that the user who does not creases database has no owner privilege on this database
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateDatabaseNegative() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+
+ // setup privileges for USER1
+ statement.execute("GRANT CREATE ON SERVER server1" + " TO ROLE create_db1");
+
+ // USER1 creates test DB
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE DATABASE " + DB1);
+
+ // verify user user1_2 has no privileges created for new database
+ Connection connectionUSER1_2 = hiveServer2.createConnection(USER1_2, USER1_2);
+ Statement statementUSER1_2 = connectionUSER1_2.createStatement();
+ verifyTablePrivilegeExistForUser(statementUSER1_2, Lists.newArrayList(USER1_2),
+ DB1, null, 0);
+
+ // verify that user user1_2 does not have any privilege on this database except create
+ try {
+ statementUSER1_2.execute("DROP DATABASE " + DB1 + " CASCADE");
+ Assert.fail("Expect dropping database to fail");
+ } catch (Exception ex) {
+ LOGGER.info("Expected Exception when dropping database " + ex.getMessage());
+ }
+
+
+ statement.close();
+ connection.close();
+
+ statementUSER1_1.close();
+ connectionUSER1_1.close();
+
+ statementUSER1_2.close();
+ connectionUSER1_2.close();
+ }
+
+ /**
+ * Verify that no owner privilege is created when its creator is an admin user
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateDatabaseAdmin() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+
+ // admin user creates test DB
+ statement.execute("CREATE DATABASE " + DB1);
+
+ // verify no privileges created for new database
+ verifyTablePrivilegeExistForUser(statement, Lists.newArrayList(admin),
+ DB1, null, 0);
+
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Verify that after dropping a database, the user who creases database has no owner privilege
+ * on this dropped database
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testDropDatabase() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+
+ // setup privileges for USER1
+ statement.execute("GRANT CREATE ON SERVER server1" + " TO ROLE create_db1");
+
+ // USER1 creates test DB and then drop it
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE DATABASE " + DB1);
+ statementUSER1_1.execute("DROP DATABASE " + DB1 + " CASCADE");
+
+ // verify owner privileges created for new database no longer exists
+ verifyTablePrivilegeExistForUser(statementUSER1_1, Lists.newArrayList(USER1_1),
+ DB1, null, 0);
+
+ statement.close();
+ connection.close();
+
+ statementUSER1_1.close();
+ connectionUSER1_1.close();
+ }
+
+
+ /**
+ * Verify that the user who creases table has owner privilege on this table
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateTable() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ // create test DB
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+ statement.execute("CREATE DATABASE " + DB1);
+
+ // setup privileges for USER1
+ statement.execute("GRANT CREATE ON DATABASE " + DB1 + " TO ROLE create_db1");
+ statement.execute("USE " + DB1);
+
+ // USER1 create table
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE TABLE " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column')");
+
+
+ // verify privileges created for new table
+ verifyTablePrivilegeExistForUser(statementUSER1_1, Lists.newArrayList(USER1_1),
+ DB1, tableName1, 1);
+
+ // verify that user has all privilege on this table, i.e., "OWNER" means "ALL"
+ // for authorization
+ statementUSER1_1.execute("INSERT INTO TABLE " + DB1 + "." + tableName1 + " VALUES (35)");
+ statementUSER1_1.execute("ALTER TABLE " + DB1 + "." + tableName1 + " RENAME TO " +
+ DB1 + "." + tableName1 + renameTag );
+
+ // alter table rename is not blocked for notification processing in upstream due to
+ // hive bug HIVE-18783, which is fixed in Hive 2.4.0 and 3.0
+ Thread.sleep(WAIT_BEFORE_TESTVERIFY);
+ statementUSER1_1.execute("DROP TABLE " + DB1 + "." + tableName1 + renameTag);
+
+ statement.close();
+ connection.close();
+
+ statementUSER1_1.close();
+ connectionUSER1_1.close();
+ }
+
+ /**
+ * Verify that the user who creases table has owner privilege on this table, but cannot
+ * access tables created by others
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateTableNegative() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ // create test DB
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+ statement.execute("CREATE DATABASE " + DB1);
+
+ // setup privileges for USER1 and USER2
+ statement.execute("GRANT CREATE ON DATABASE " + DB1 + " TO ROLE create_db1");
+ statement.execute("USE " + DB1);
+
+ // USER1 create table
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE TABLE " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column')");
+
+ // verify user1_2 does not have privileges on table created by user1_1
+ Connection connectionUSER1_2 = hiveServer2.createConnection(USER1_2, USER1_2);
+ Statement statementUSER1_2 = connectionUSER1_2.createStatement();
+ verifyTablePrivilegeExistForUser(statementUSER1_2, Lists.newArrayList(USER1_2),
+ DB1, tableName1, 0);
+
+ // verify that user user1_2 does not have any privilege on this table
+ try {
+ statementUSER1_2.execute("INSERT INTO TABLE " + DB1 + "." + tableName1 + " VALUES (35)");
+ Assert.fail("Expect table insert to fail");
+ } catch (Exception ex) {
+ LOGGER.info("Expected Exception when inserting table: " + ex.getMessage());
+ }
+
+ try {
+ statementUSER1_2.execute("ALTER TABLE " + DB1 + "." + tableName1 + " RENAME TO " +
+ DB1 + "." + tableName1 + renameTag);
+ Assert.fail("Expect table rename to fail");
+ } catch (Exception ex) {
+ LOGGER.info("Expected Exception when renaming table: " + ex.getMessage());
+ }
+
+ try {
+ statementUSER1_2.execute("DROP TABLE " + DB1 + "." + tableName1 );
+ Assert.fail("Expect table drop to fail");
+ } catch (Exception ex) {
+ LOGGER.info("Expected Exception when dropping table: " + ex.getMessage());
+ }
+
+ statement.close();
+ connection.close();
+
+ statementUSER1_1.close();
+ connectionUSER1_1.close();
+
+ statementUSER1_2.close();
+ connectionUSER1_2.close();
+ }
+
+ /**
+ * Verify that no owner privilege is created on table created by an admin user
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateTableAdmin() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+
+ // admin creates test DB and then drop it
+ statement.execute("CREATE DATABASE " + DB1);
+ statement.execute("CREATE TABLE " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column')");
+
+ // verify no owner privileges created for new table
+ verifyTablePrivilegeExistForUser(statement, Lists.newArrayList(admin),
+ DB1, tableName1, 0);
+
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Verify that the user who creases table and then drops it has no owner privilege on this table
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testDropTable() throws Exception {
+ dbNames = new String[]{DB1};
+ roles = new String[]{"admin_role", "create_db1"};
+
+ // create required roles
+ setupUserRoles(roles, statement);
+
+ // create test DB
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+ statement.execute("CREATE DATABASE " + DB1);
+
+ // setup privileges for USER1
+ statement.execute("GRANT CREATE ON DATABASE " + DB1 + " TO ROLE create_db1");
+
+ // USER1 create table
+ Connection connectionUSER1_1 = hiveServer2.createConnection(USER1_1, USER1_1);
+ Statement statementUSER1_1 = connectionUSER1_1.createStatement();
+ statementUSER1_1.execute("CREATE TABLE " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column', value string)");
+ statementUSER1_1.execute("DROP TABLE " + DB1 + "." + tableName1);
+
+ // verify privileges created for new table
+ verifyTablePrivilegeExistForUser(statementUSER1_1, Lists.newArrayList(USER1_1),
+ DB1, tableName1, 0);
+
+ statement.close();
+ connection.close();
+ }
+
+
+
+ // TODO: once hive supports alter table set owner, need to add testing cases for owner
+ // privilege associated with role
+
+ // Create test roles
+ private void setupUserRoles(String[] roles, Statement statement) throws Exception {
+ Set<String> userRoles = Sets.newHashSet(roles);
+ userRoles.remove("admin_role");
+
+ for (String roleName : userRoles) {
+ statement.execute("CREATE ROLE " + roleName);
+ statement.execute("GRANT ROLE " + roleName + " to GROUP " + USERGROUP1);
+ }
+ }
+
+ // verify given table is part of every user in the list
+ private void verifyTablePrivilegeExistForUser(Statement statement,
+ List<String> users, String dbName, String tableName, int expectedResultCount) throws Exception {
+
+ for (String userName : users) {
+ String command;
+
+ if (tableName == null) {
+ command = "SHOW GRANT USER " + userName + " ON DATABASE " + dbName;
+ } else {
+ command = "SHOW GRANT USER " + userName + " ON TABLE " + dbName + "." + tableName;
+ }
+
+ ResultSet resultSet = statement.executeQuery(command);
+
+ int resultSize = 0;
+ while(resultSet.next()) {
+ resultSize ++;
+
+ assertThat(resultSet.getString(1), equalToIgnoringCase(dbName)); // db name
+
+ if (tableName != null) {
+ assertThat(resultSet.getString(2), equalToIgnoringCase(tableName)); // table name
+ }
+
+ assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition
+ assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column
+ assertThat(resultSet.getString(5), equalToIgnoringCase(userName));//principalName
+ assertThat(resultSet.getString(6), equalToIgnoringCase("user"));//principalType
+ assertThat(resultSet.getString(7), equalToIgnoringCase("owner"));
+ assertThat(resultSet.getBoolean(8), is(ownerPrivilegeGrantEnabled));//grantOption
+ }
+
+ assertEquals(expectedResultCount, resultSize);
+
+ resultSet.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivilegesWithGrantOption.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivilegesWithGrantOption.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivilegesWithGrantOption.java
new file mode 100644
index 0000000..4de7475
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestOwnerPrivilegesWithGrantOption.java
@@ -0,0 +1,30 @@
+/**
+ * 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 org.junit.BeforeClass;
+
+public class TestOwnerPrivilegesWithGrantOption extends TestOwnerPrivileges {
+ @BeforeClass
+ public static void setup() throws Exception {
+ ownerPrivilegeGrantEnabled = true;
+
+ TestOwnerPrivileges.setup();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/dbf83ab2/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
index 100219b..9b4f4da 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
@@ -202,6 +202,8 @@ public abstract class TestHDFSIntegrationBase {
protected static Boolean hdfsSyncEnabled = true;
protected static Boolean hiveSyncOnCreate = false;
protected static Boolean hiveSyncOnDrop = true;
+ protected static Boolean ownerPrivilegeEnabled = false;
+ protected static Boolean ownerPrivilegeGrantEnabled = false;
protected static Configuration hadoopConf;
protected static final Map<String, String> sentryProperties = Maps.newHashMap();
protected static Configuration sentryConf = new Configuration(false);
@@ -875,7 +877,15 @@ public abstract class TestHDFSIntegrationBase {
"org.apache.sentry.api.service.thrift.SentryPolicyStoreProcessorFactory,org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
sentryProperties.put("sentry.policy.store.plugins", "org.apache.sentry.hdfs.SentryPlugin");
}
- for (Map.Entry<String, String> entry : sentryProperties.entrySet()) {
+ if(ownerPrivilegeEnabled) {
+ sentryProperties.put("sentry.enable.owner.privileges", "true");
+
+ if(ownerPrivilegeGrantEnabled) {
+ sentryProperties.put("sentry.grant.owner.privileges.with.grant", "true");
+ }
+ }
+
+ for (Map.Entry<String, String> entry : sentryProperties.entrySet()) {
sentryConf.set(entry.getKey(), entry.getValue());
}
sentryServer = SentrySrvFactory.create(SentrySrvFactory.SentrySrvType.INTERNAL_SERVER,