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,