You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by lv...@apache.org on 2018/04/25 21:47:44 UTC

[1/7] impala git commit: IMPALA-6887: Typo in authz-policy.ini.template

Repository: impala
Updated Branches:
  refs/heads/2.x 3acb8f984 -> c66096523


IMPALA-6887: Typo in authz-policy.ini.template

Before: alter_functionl_text_lzo
After: alter_functional_text_lzo

This patch also adds missing test cases for ALTER privilege on
functional_text_lzo database.

Testing:
- Ran all front-end tests

Change-Id: I6aea8d71dda39838e9e70160018ce2c5fc73df21
Reviewed-on: http://gerrit.cloudera.org:8080/10113
Reviewed-by: Bharath Vissapragada <bh...@cloudera.com>
Tested-by: Impala Public Jenkins <im...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/c6609652
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/c6609652
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/c6609652

Branch: refs/heads/2.x
Commit: c66096523d455901055b040c6c17759d08b06bc0
Parents: c226f0e
Author: Fredy wijaya <fw...@cloudera.com>
Authored: Wed Apr 18 18:19:23 2018 -0700
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 .../impala/analysis/AuthorizationTest.java      | 20 ++++++++++++++++++++
 fe/src/test/resources/authz-policy.ini.template |  2 +-
 2 files changed, 21 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/c6609652/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index c82b4c8..e5b7702 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -1472,6 +1472,26 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("ALTER TABLE functional.alltypeserror SET CACHED IN 'testPool'");
     AuthzOk("ALTER TABLE functional.alltypeserror RECOVER PARTITIONS");
 
+    // User has ALTER privilege on functional_text_lzo database.
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror ADD COLUMNS (c1 int)");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror REPLACE COLUMNS (c1 int)");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror CHANGE id c1 int");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror DROP id");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror RENAME TO " +
+        "functional_seq_snap.t1");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror SET FILEFORMAT PARQUET");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror SET LOCATION " +
+        "'/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror SET TBLPROPERTIES " +
+        "('a'='b', 'c'='d')");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror SET LOCATION " +
+        "'hdfs://localhost:20500/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror " +
+        "PARTITION(year=2009, month=1) SET LOCATION " +
+        "'hdfs://localhost:20500/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror SET CACHED IN 'testPool'");
+    AuthzOk("ALTER TABLE functional_text_lzo.alltypeserror RECOVER PARTITIONS");
+
     // Alter table and set location to a path the user does not have access to.
     // User needs ALTER on table and ALL on URI.
     AuthzError("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +

http://git-wip-us.apache.org/repos/asf/impala/blob/c6609652/fe/src/test/resources/authz-policy.ini.template
----------------------------------------------------------------------
diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template
index 26ed70b..e26ee55 100644
--- a/fe/src/test/resources/authz-policy.ini.template
+++ b/fe/src/test/resources/authz-policy.ini.template
@@ -68,7 +68,7 @@ alter_functional_alltypes_view =\
     server=server1->db=functional->table=alltypes_view->action=alter
 insert_functional_text_lzo = server=server1->db=functional_text_lzo->action=insert
 create_functional_text_lzo = server=server1->db=functional_text_lzo->action=create
-alter_functionl_text_lzo = server=server1->db=functional_text_lzo->action=alter
+alter_functional_text_lzo = server=server1->db=functional_text_lzo->action=alter
 drop_functional_text_lzo = server=server1->db=functional_text_lzo->action=drop
 select_column_level_functional =\
     server=server1->db=functional->table=alltypessmall->column=id->action=select,\


[3/7] impala git commit: IMPALA-6647: Add CREATE fine-grained privilege

Posted by lv...@apache.org.
IMPALA-6647: Add CREATE fine-grained privilege

This patch allows executing CREATE statements by granting CREATE
privilege.

These are the new GRANT/REVOKE statements introduced at server and
database scopes.

GRANT CREATE on SERVER svr TO ROLE testrole;
GRANT CREATE on DATABASE db TO ROLE testrole;

REVOKE CREATE on SERVER svr FROM ROLE testrole;
REVOKE CREATE on DATABASE db FROM ROLE testrole;

Testing:
- Ran front-end tests

Change-Id: Id540e78fc9201fc1b4e6cac9b81ea54b8ae9eecd
Reviewed-on: http://gerrit.cloudera.org:8080/9738
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/9f90a658
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/9f90a658
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/9f90a658

Branch: refs/heads/2.x
Commit: 9f90a6583c1feacdaade1528cd800d3094d93b15
Parents: f2a8924
Author: Fredy Wijaya <fw...@cloudera.com>
Authored: Tue Mar 20 18:15:34 2018 -0500
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 common/thrift/CatalogObjects.thrift             |   3 +-
 fe/src/main/cup/sql-parser.cup                  |   2 +
 .../impala/analysis/CreateFunctionStmtBase.java |   9 +-
 .../impala/analysis/DropFunctionStmt.java       |   2 +-
 .../apache/impala/analysis/PrivilegeSpec.java   |   9 +-
 .../authorization/AuthorizationChecker.java     |  11 +-
 .../impala/authorization/AuthorizeableFn.java   |  17 ++-
 .../apache/impala/authorization/Privilege.java  |   3 +-
 .../impala/analysis/AnalyzeAuthStmtsTest.java   |  20 ++-
 .../apache/impala/analysis/AnalyzeDDLTest.java  |   9 +-
 .../impala/analysis/AuthorizationTest.java      | 122 ++++++++++++++++---
 .../org/apache/impala/analysis/ParserTest.java  |   5 +
 fe/src/test/resources/authz-policy.ini.template |   6 +-
 13 files changed, 176 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/common/thrift/CatalogObjects.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift
index badad28..9cacd6e 100644
--- a/common/thrift/CatalogObjects.thrift
+++ b/common/thrift/CatalogObjects.thrift
@@ -470,7 +470,8 @@ enum TPrivilegeLevel {
   ALL,
   INSERT,
   SELECT,
-  REFRESH
+  REFRESH,
+  CREATE
 }
 
 // Represents a privilege in an authorization policy. Privileges contain the level

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/cup/sql-parser.cup
----------------------------------------------------------------------
diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup
index 4490a8c..d6c219b 100644
--- a/fe/src/main/cup/sql-parser.cup
+++ b/fe/src/main/cup/sql-parser.cup
@@ -962,6 +962,8 @@ privilege ::=
   {: RESULT = TPrivilegeLevel.INSERT; :}
   | KW_REFRESH
   {: RESULT = TPrivilegeLevel.REFRESH; :}
+  | KW_CREATE
+  {: RESULT = TPrivilegeLevel.CREATE; :}
   | KW_ALL
   {: RESULT = TPrivilegeLevel.ALL; :}
   ;

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/analysis/CreateFunctionStmtBase.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/CreateFunctionStmtBase.java b/fe/src/main/java/org/apache/impala/analysis/CreateFunctionStmtBase.java
index c03387c..cd86e93 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CreateFunctionStmtBase.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CreateFunctionStmtBase.java
@@ -146,25 +146,22 @@ public abstract class CreateFunctionStmtBase extends StatementBase {
       fn_ = createFunction(fnName_, null, null, false);
     }
 
-    // For now, if authorization is enabled, the user needs ALL on the server
-    // to create functions.
-    // TODO: this is not the right granularity but acceptable for now.
     analyzer.registerPrivReq(new PrivilegeRequest(
-        new AuthorizeableFn(fn_.signatureString()), Privilege.ALL));
+        new AuthorizeableFn(fn_.dbName(), fn_.signatureString()), Privilege.CREATE));
 
     if (ImpaladCatalog.getBuiltinsDb().containsFunction(fn_.getName())) {
       throw new AnalysisException("Function cannot have the same name as a builtin: " +
           fn_.getFunctionName().getFunction());
     }
 
-    db_ = analyzer.getDb(fn_.dbName(), Privilege.CREATE);
+    db_ = analyzer.getDb(fn_.dbName(), true);
     Function existingFn = db_.getFunction(fn_, Function.CompareMode.IS_INDISTINGUISHABLE);
     if (existingFn != null && !ifNotExists_) {
       throw new AnalysisException(Analyzer.FN_ALREADY_EXISTS_ERROR_MSG +
           existingFn.signatureString());
     }
 
-    location_.analyze(analyzer, Privilege.CREATE, FsAction.READ);
+    location_.analyze(analyzer, Privilege.ALL, FsAction.READ);
     fn_.setLocation(location_);
 
     // Check the file type from the binary type to infer the type of the UDA

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
index 7a4fa53..1a533d1 100644
--- a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
@@ -89,7 +89,7 @@ public class DropFunctionStmt extends StatementBase {
     // to drop functions.
     // TODO: this is not the right granularity but acceptable for now.
     analyzer.registerPrivReq(new PrivilegeRequest(
-        new AuthorizeableFn(desc_.signatureString()), Privilege.ALL));
+        new AuthorizeableFn(desc_.dbName(), desc_.signatureString()), Privilege.ALL));
 
     Db db =  analyzer.getDb(desc_.dbName(), Privilege.DROP, false);
     if (db == null && !ifExists_) {

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index cbc3c80..fcece28 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -189,8 +189,9 @@ public class PrivilegeSpec implements ParseNode {
     switch (scope_) {
       case SERVER:
         if (privilegeLevel_ != TPrivilegeLevel.ALL &&
-            privilegeLevel_ != TPrivilegeLevel.REFRESH) {
-          throw new AnalysisException("Only 'ALL' or 'REFRESH' privilege " +
+            privilegeLevel_ != TPrivilegeLevel.REFRESH &&
+            privilegeLevel_ != TPrivilegeLevel.CREATE) {
+          throw new AnalysisException("Only 'ALL', 'REFRESH', or 'CREATE' privilege " +
               "may be applied at SERVER scope in privilege spec.");
         }
         break;
@@ -269,11 +270,15 @@ public class PrivilegeSpec implements ParseNode {
    * 1. The table name is not valid.
    * 2. Table is not loaded in the catalog.
    * 3. Table does not exist.
+   * 4. The privilege level is not supported on tables, e.g. CREATE.
    */
   private Table analyzeTargetTable(Analyzer analyzer) throws AnalysisException {
     Preconditions.checkState(scope_ == TPrivilegeScope.TABLE ||
         scope_ == TPrivilegeScope.COLUMN);
     Preconditions.checkState(!Strings.isNullOrEmpty(tableName_.getTbl()));
+    if (privilegeLevel_ == TPrivilegeLevel.CREATE) {
+      throw new AnalysisException("Create-level privileges on tables are not supported.");
+    }
     Table table = null;
     try {
       dbName_ = analyzer.getTargetDbName(tableName_);

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
index b6fc299..04ac4ef 100644
--- a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
+++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
@@ -127,8 +127,8 @@ public class AuthorizationChecker {
     if (!hasAccess(user, privilegeRequest)) {
       if (privilegeRequest.getAuthorizeable() instanceof AuthorizeableFn) {
         throw new AuthorizationException(String.format(
-            "User '%s' does not have privileges to CREATE/DROP functions.",
-            user.getName()));
+            "User '%s' does not have privileges to CREATE/DROP functions in: %s",
+            user.getName(), privilegeRequest.getName()));
       }
 
       Privilege privilege = privilegeRequest.getPrivilege();
@@ -184,7 +184,12 @@ public class AuthorizationChecker {
         }
       }
       return false;
-    } else if (request.getPrivilege() == Privilege.CREATE && authorizeables.size() > 1) {
+    // AuthorizeableFn is special due to Sentry not having the concept of a function in
+    // DBModelAuthorizable.AuthorizableType. As a result, the list of authorizables for
+    // an AuthorizeableFn only contains the server and database, but not the function
+    // itself. So there is no need to remove the last authorizeable here.
+    } else if (request.getPrivilege() == Privilege.CREATE && authorizeables.size() > 1 &&
+        !(request.getAuthorizeable() instanceof AuthorizeableFn)) {
       // CREATE on an object requires CREATE on the parent,
       // so don't check access on the object we're creating.
       authorizeables.remove(authorizeables.size() - 1);

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/authorization/AuthorizeableFn.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizeableFn.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizeableFn.java
index e74b435..e8bc6ef 100644
--- a/fe/src/main/java/org/apache/impala/authorization/AuthorizeableFn.java
+++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizeableFn.java
@@ -19,6 +19,7 @@ package org.apache.impala.authorization;
 
 import java.util.List;
 
+import com.google.common.base.Strings;
 import org.apache.sentry.core.model.db.DBModelAuthorizable;
 
 import com.google.common.base.Preconditions;
@@ -29,17 +30,25 @@ import com.google.common.collect.Lists;
  */
 public class AuthorizeableFn extends Authorizeable {
   private final String fnName_;
+  private final org.apache.sentry.core.model.db.Database database_;
 
-  public AuthorizeableFn(String fnName) {
-    Preconditions.checkState(fnName != null && !fnName.isEmpty());
+  public AuthorizeableFn(String dbName, String fnName) {
+    Preconditions.checkState(!Strings.isNullOrEmpty(dbName));
+    Preconditions.checkState(!Strings.isNullOrEmpty(fnName));
+    database_ = new org.apache.sentry.core.model.db.Database(dbName);
     fnName_ = fnName;
   }
 
   @Override
   public List<DBModelAuthorizable> getHiveAuthorizeableHierarchy() {
-    return Lists.newArrayList();
+    return Lists.newArrayList((DBModelAuthorizable) database_);
   }
 
   @Override
-  public String getName() { return fnName_; }
+  public String getName() { return database_.getName() + "." + fnName_; }
+
+  @Override
+  public String getDbName() { return database_.getName(); }
+
+  public String getFnName() { return fnName_; };
 }

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/main/java/org/apache/impala/authorization/Privilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/Privilege.java b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
index f82008c..b6fa14c 100644
--- a/fe/src/main/java/org/apache/impala/authorization/Privilege.java
+++ b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
@@ -28,7 +28,7 @@ public enum Privilege {
   ALL(SentryAction.ALL, false),
   ALTER(SentryAction.ALL, false),
   DROP(SentryAction.ALL, false),
-  CREATE(SentryAction.ALL, false),
+  CREATE(SentryAction.CREATE, false),
   INSERT(SentryAction.INSERT, false),
   SELECT(SentryAction.SELECT, false),
   REFRESH(SentryAction.REFRESH, false),
@@ -54,6 +54,7 @@ public enum Privilege {
     SELECT("select"),
     INSERT("insert"),
     REFRESH("refresh"),
+    CREATE("create"),
     ALL("*");
 
     private final String value;

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index f749e1f..825ed35 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -165,8 +165,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL' or 'REFRESH' privilege may be applied at SERVER scope " +
-          "in privilege spec.");
+          "Only 'ALL', 'REFRESH', or 'CREATE' privilege may be applied at SERVER " +
+          "scope in privilege spec.");
       AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -181,8 +181,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL' or 'REFRESH' privilege may be applied at SERVER scope " +
-          "in privilege spec.");
+          "Only 'ALL', 'REFRESH', or 'CREATE' privilege may be applied at SERVER " +
+          "scope in privilege spec.");
       AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -233,6 +233,18 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalysisError(String.format(
           "%s REFRESH ON URI 'hdfs:////abc//123' %s myrole", formatArgs),
           "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
+
+      // CREATE privilege
+      AnalyzesOk(String.format("%s CREATE ON SERVER %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s CREATE ON SERVER server1 %s myrole", formatArgs));
+      AnalyzesOk(String.format(
+          "%s CREATE ON DATABASE functional %s myrole", formatArgs));
+      AnalysisError(String.format(
+          "%s CREATE ON TABLE functional.alltypes %s myrole", formatArgs),
+          "Create-level privileges on tables are not supported.");
+      AnalysisError(String.format(
+          "%s CREATE ON URI 'hdfs:////abc//123' %s myrole", formatArgs),
+          "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
     }
 
     AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
index 8eaf674..8f9e384 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
@@ -3114,11 +3114,12 @@ public class AnalyzeDDLTest extends FrontendTestBase {
         "Could not find function FakePrepare(impala_udf::FunctionContext*, "+
         "impala_udf::FunctionContext::FunctionStateScope) in: ");
 
+    // TODO: https://issues.apache.org/jira/browse/IMPALA-6724
     // Try to create a function with the same name as a builtin
-    AnalysisError("create function sin(double) RETURNS double" + udfSuffix,
-        "Function cannot have the same name as a builtin: sin");
-    AnalysisError("create function sin() RETURNS double" + udfSuffix,
-        "Function cannot have the same name as a builtin: sin");
+    // AnalysisError("create function sin(double) RETURNS double" + udfSuffix,
+    //    "Function cannot have the same name as a builtin: sin");
+    // AnalysisError("create function sin() RETURNS double" + udfSuffix,
+    //    "Function cannot have the same name as a builtin: sin");
 
     // Try to create with a bad location
     AnalysisError("create function foo() RETURNS int LOCATION 'bad-location' SYMBOL='c'",

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index a309880..40865c8 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -96,7 +96,7 @@ public class AuthorizationTest extends FrontendTestBase {
   //   No permissions on database 'functional_rc'
   //   Only column level permissions in 'functional_avro':
   //     SELECT permissions on columns ('id') on 'functional_avro.alltypessmall'
-  //   REFRESH permissions on 'functional_text_lzo' database
+  //   REFRESH, INSERT, CREATE permissions on 'functional_text_lzo' database
   public final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini";
   public final static User USER = new User(System.getProperty("user.name"));
 
@@ -270,6 +270,30 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name("view_view");
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // insert_functional_text_lzo
+    roleName = "insert_functional_text_lzo";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.INSERT,
+        TPrivilegeScope.DATABASE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional_text_lzo");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
+    // create_functional_text_lzo
+    roleName = "create_functional_text_lzo";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.CREATE,
+        TPrivilegeScope.DATABASE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional_text_lzo");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // all newdb w/ all on URI
     roleName = "all_newdb";
     sentryService.createRole(USER, roleName, true);
@@ -295,6 +319,13 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.URI,
+        false);
+    privilege.setServer_name("server1");
+    privilege.setUri("hdfs://localhost:20500/test-warehouse/libTestUdfs.so");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // all tpch
     roleName = "all_tpch";
     sentryService.createRole(USER, roleName, true);
@@ -942,12 +973,24 @@ public class AuthorizationTest extends FrontendTestBase {
     } catch (AnalysisException e) {
       Assert.assertEquals(e.getMessage(), "Table already exists: tpch.lineitem");
     }
+    // User has CREATE privilege on functional_text_lzo database.
+    AuthzOk("create table functional_text_lzo.new_table (i int)");
 
     // Create table AS SELECT positive and negative cases for SELECT privilege.
     AuthzOk("create table tpch.new_table as select * from functional.alltypesagg");
+    // User has CREATE and INSERT privileges on functional_text_lzo database and SELECT
+    // privilege on functional.alltypesagg table.
+    AuthzOk("create table functional_text_lzo.new_table as " +
+        "select * from functional.alltypesagg");
     AuthzError("create table tpch.new_table as select * from functional.alltypes",
         "User '%s' does not have privileges to execute 'SELECT' on: " +
         "functional.alltypes");
+    // User has CREATE privilege on functional_text_lzo database, SELECT privilege on
+    // functional.alltypes table but no INSERT privilege on functional_text_lzo database.
+    AuthzError("create table functional_text_lzo.new_table as " +
+        "select * from functional.alltypes",
+        "User '%s' does not have privileges to execute 'SELECT' on: " +
+        "functional.alltypes");
 
     // CTAS with a subquery.
     AuthzOk("create table tpch.new_table as select * from functional.alltypesagg " +
@@ -1059,6 +1102,10 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("create view tpch.new_view as select * from functional.alltypesagg");
     AuthzOk("create view tpch.new_view (a, b, c) as " +
         "select int_col, string_col, timestamp_col from functional.alltypesagg");
+    // User has CREATE and INSERT privileges on functional_text_lzo database and
+    // SELECT privilege on functional.alltypesagg table.
+    AuthzOk("create view functional_text_lzo.new_view as " +
+        "select * from functional.alltypesagg");
     // Create view IF NOT EXISTS, user has permission and table exists.
     AuthzOk("create view if not exists tpch.lineitem as " +
         "select * from functional.alltypesagg");
@@ -2043,27 +2090,40 @@ public class AuthorizationTest extends FrontendTestBase {
   public void TestFunction() throws Exception {
     // First try with the less privileged user.
     AnalysisContext ctx = createAnalysisCtx(ctx_.authzConfig, USER.getName());
+
+    // User has CREATE privilege on functional_text_lzo database and ALL privilege
+    // on /test-warehouse/libTestUdfs.so URI.
+    AuthzOk(ctx, "create function functional_text_lzo.f() returns int location " +
+        "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'");
+
     AuthzError(ctx, "show functions",
         "User '%s' does not have privileges to access: default");
     AuthzOk(ctx, "show functions in tpch");
 
     AuthzError(ctx, "create function f() returns int location " +
         "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-        "User '%s' does not have privileges to CREATE/DROP functions.");
+        "User '%s' does not have privileges to CREATE/DROP functions in: default.f()");
 
-    AuthzError(ctx, "create function tpch.f() returns int location " +
-        "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-        "User '%s' does not have privileges to CREATE/DROP functions.");
+    // User has ALL privilege on tpch database and ALL privilege on
+    // /test-warehouse/libTestUdfs.so URI.
+    AuthzOk(ctx, "create function tpch.f() returns int location " +
+        "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'");
 
     AuthzError(ctx, "create function notdb.f() returns int location " +
         "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-        "User '%s' does not have privileges to CREATE/DROP functions.");
+        "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()");
 
     AuthzError(ctx, "drop function if exists f()",
-        "User '%s' does not have privileges to CREATE/DROP functions.");
+        "User '%s' does not have privileges to CREATE/DROP functions in: default.f()");
 
     AuthzError(ctx, "drop function notdb.f()",
-        "User '%s' does not have privileges to CREATE/DROP functions.");
+        "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()");
+
+    // User does not have ALL privilege on SERVER and tries to create a function with
+    // the same name as the built-in function.
+    AuthzError(ctx, "create function sin(double) returns double location " +
+        "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
+        "Cannot modify system database.");
 
     // TODO: Add test support for dynamically changing privileges for
     // file-based policy.
@@ -2105,13 +2165,6 @@ public class AuthorizationTest extends FrontendTestBase {
       sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
       ctx_.catalog.reset();
 
-      AuthzError(ctx, "create function tpch.f() returns int location " +
-          "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-          "User '%s' does not have privileges to CREATE/DROP functions.");
-
-      // Couldn't create tpch.f() but can run it.
-      AuthzOk("select tpch.f()");
-
       //Other tests don't expect tpch to contain functions
       //Specifically, if these functions are not cleaned up, TestDropDatabase() will fail
       ctx_.catalog.removeFunction(ScalarFunction.createForTesting("default", "f",
@@ -2280,6 +2333,45 @@ public class AuthorizationTest extends FrontendTestBase {
         "TBLPROPERTIES ('kudu.master_addresses'='127.0.0.1', 'kudu.table_name'='tbl')");
   }
 
+  @Test
+  public void TestServerLevelCreate() throws ImpalaException {
+    // TODO: Add test support for dynamically changing privileges for
+    // file-based policy.
+    if (ctx_.authzConfig.isFileBasedPolicy()) return;
+
+    SentryPolicyService sentryService =
+        new SentryPolicyService(ctx_.authzConfig.getSentryConfig());
+
+    // User has CREATE privilege on server.
+    String roleName = "create_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.CREATE,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+
+      AuthzOk("create database newdb");
+      AuthzOk("create database newdb location " +
+          "'hdfs://localhost:20500/test-warehouse/new_table'");
+      AuthzOk("create table functional_avro.newtable (i int)");
+      AuthzOk("create view functional_avro.newview as " +
+          "select * from functional.alltypesagg");
+      AuthzOk("create function functional_avro.f() returns int location " +
+          "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'");
+      // User does not have INSERT privilege on functional_avro database.
+      AuthzError("create table functional_avro.newtable as " +
+          "select * from functional.alltypesagg",
+          "User '%s' does not have privileges to execute 'INSERT' on: " +
+          "functional_avro.newtable");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
+    }
+  }
+
   private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user)
       throws ImpalaException {
     Frontend fe = new Frontend(authzConfig, ctx_.catalog);

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
index aefa8e2..e61266e 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
@@ -3581,6 +3581,11 @@ public class ParserTest extends FrontendTestBase {
       ParsesOk(String.format("%s REFRESH ON DATABASE foo %s myRole", formatStr));
       ParsesOk(String.format("%s REFRESH ON TABLE foo %s myRole", formatStr));
 
+      // CREATE privilege.
+      ParsesOk(String.format("%s CREATE ON SERVER %s myRole", formatStr));
+      ParsesOk(String.format("%s CREATE ON SERVER foo %s myRole", formatStr));
+      ParsesOk(String.format("%s CREATE ON DATABASE foo %s myRole", formatStr));
+
       // Server scope does not accept a name.
       ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr));
       ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr));

http://git-wip-us.apache.org/repos/asf/impala/blob/9f90a658/fe/src/test/resources/authz-policy.ini.template
----------------------------------------------------------------------
diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template
index f3c7c1f..aeb3911 100644
--- a/fe/src/test/resources/authz-policy.ini.template
+++ b/fe/src/test/resources/authz-policy.ini.template
@@ -26,7 +26,8 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\
           insert_parquet, new_table_uri, tpch_data_uri, select_column_level_functional,\
           select_column_level_functional_avro, upper_case_uri,\
           refresh_functional_text_lzo, refresh_functional_alltypesagg,\
-          refresh_functional_view_view
+          refresh_functional_view_view, insert_functional_text_lzo,\
+          create_functional_text_lzo, libtestudfs_uri
 auth_to_local_group = test_role
 server_admin = all_server
 
@@ -54,6 +55,8 @@ refresh_functional_alltypesagg =\
     server=server1->db=functional->table=alltypesagg->action=refresh
 refresh_functional_view_view =\
     server=server1->db=functional->table=view_view->action=refresh
+insert_functional_text_lzo = server=server1->db=functional_text_lzo->action=insert
+create_functional_text_lzo = server=server1->db=functional_text_lzo->action=create
 select_column_level_functional =\
     server=server1->db=functional->table=alltypessmall->column=id->action=select,\
     server=server1->db=functional->table=alltypessmall->column=int_col->action=select,\
@@ -80,6 +83,7 @@ select_column_level_functional_avro =\
 new_table_uri = server=server1->uri=hdfs://localhost:20500/test-warehouse/new_table
 tpch_data_uri = server=server1->uri=hdfs://localhost:20500/test-warehouse/tpch.lineitem
 upper_case_uri = server=server1->uri=hdfs://localhost:20500/test-warehouse/UPPER_CASE
+libtestudfs_uri = server=server1->uri=hdfs://localhost:20500/test-warehouse/libTestUdfs.so
 
 # This section allows for an admin specified mapping of users -> groups rather than using
 # the built-in hadoop group mapping. This section is only applicable if using the


[4/7] impala git commit: IMPALA-6643: Add REFRESH fine-grained privilege

Posted by lv...@apache.org.
IMPALA-6643: Add REFRESH fine-grained privilege

Before this patch, ALL privilege was required to execute INVALIDATE
METADATA and having any privilege allowed executing REFRESH <table>
and INVALIDATE METADATA <table>. With this patch, REFRESH privilege
is now required to execute INVALIDATE METADATA or REFRESH statement.

These are the new GRANT/REVOKE statements introduced at server,
database, and table scopes.

GRANT REFRESH on SERVER svr TO ROLE testrole;
GRANT REFRESH on DATABASE db TO ROLE testrole;
GRANT REFRESH on TABLE db.tbl TO ROLE testrole;

REVOKE REFRESH on SERVER svr FROM ROLE testrole;
REVOKE REFRESH on DATABASE db FROM ROLE testrole;
REVOKE REFRESH on TABLE db.tbl FROM ROLE testrole;

Testing:
- Ran front-end tests

Change-Id: I4c3c5a51fe493d39fd719c7a388d4d5760049ce4
Reviewed-on: http://gerrit.cloudera.org:8080/9589
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/f2a89249
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/f2a89249
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/f2a89249

Branch: refs/heads/2.x
Commit: f2a8924974a5ef970279f6fdf3760804ede650b0
Parents: 3acb8f9
Author: Fredy Wijaya <fw...@cloudera.com>
Authored: Mon Mar 12 16:25:47 2018 -0500
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 common/thrift/CatalogObjects.thrift             |   3 +-
 fe/src/main/cup/sql-parser.cup                  |   2 +
 .../apache/impala/analysis/PrivilegeSpec.java   |   7 +-
 .../impala/analysis/ResetMetadataStmt.java      |  10 +-
 .../authorization/AuthorizationChecker.java     |  11 +-
 .../apache/impala/authorization/Privilege.java  |  52 +++++--
 .../impala/analysis/AnalyzeAuthStmtsTest.java   |  18 ++-
 .../impala/analysis/AuthorizationTest.java      | 137 +++++++++++++++----
 .../org/apache/impala/analysis/ParserTest.java  |   6 +
 fe/src/test/resources/authz-policy.ini.template |   9 +-
 10 files changed, 204 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/common/thrift/CatalogObjects.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift
index 8733af3..badad28 100644
--- a/common/thrift/CatalogObjects.thrift
+++ b/common/thrift/CatalogObjects.thrift
@@ -469,7 +469,8 @@ enum TPrivilegeScope {
 enum TPrivilegeLevel {
   ALL,
   INSERT,
-  SELECT
+  SELECT,
+  REFRESH
 }
 
 // Represents a privilege in an authorization policy. Privileges contain the level

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/main/cup/sql-parser.cup
----------------------------------------------------------------------
diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup
index 46a1d32..4490a8c 100644
--- a/fe/src/main/cup/sql-parser.cup
+++ b/fe/src/main/cup/sql-parser.cup
@@ -960,6 +960,8 @@ privilege ::=
   {: RESULT = TPrivilegeLevel.SELECT; :}
   | KW_INSERT
   {: RESULT = TPrivilegeLevel.INSERT; :}
+  | KW_REFRESH
+  {: RESULT = TPrivilegeLevel.REFRESH; :}
   | KW_ALL
   {: RESULT = TPrivilegeLevel.ALL; :}
   ;

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index a21af93..cbc3c80 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -188,9 +188,10 @@ public class PrivilegeSpec implements ParseNode {
 
     switch (scope_) {
       case SERVER:
-        if (privilegeLevel_ != TPrivilegeLevel.ALL) {
-          throw new AnalysisException("Only 'ALL' privilege may be applied at " +
-              "SERVER scope in privilege spec.");
+        if (privilegeLevel_ != TPrivilegeLevel.ALL &&
+            privilegeLevel_ != TPrivilegeLevel.REFRESH) {
+          throw new AnalysisException("Only 'ALL' or 'REFRESH' privilege " +
+              "may be applied at SERVER scope in privilege spec.");
         }
         break;
       case DATABASE:

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java b/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
index e070d51..a985734 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
@@ -97,7 +97,7 @@ public class ResetMetadataStmt extends StatementBase {
         // Verify the user has privileges to access this table. Will throw if the parent
         // database does not exists. Don't call getTable() to avoid loading the table
         // metadata if it is not yet in this impalad's catalog cache.
-        if (!analyzer.dbContainsTable(dbName, tableName_.getTbl(), Privilege.ANY)) {
+        if (!analyzer.dbContainsTable(dbName, tableName_.getTbl(), Privilege.REFRESH)) {
           // Only throw an exception when the table does not exist for refresh statements
           // since 'invalidate metadata' should add/remove tables created/dropped external
           // to Impala.
@@ -110,10 +110,14 @@ public class ResetMetadataStmt extends StatementBase {
       } else {
         // Verify the user has privileges to access this table.
         analyzer.registerPrivReq(new PrivilegeRequestBuilder()
-            .onTable(dbName, tableName_.getTbl()).any().toRequest());
+            .onTable(dbName, tableName_.getTbl()).allOf(Privilege.REFRESH)
+            .toRequest());
       }
+    } else if (database_ != null) {
+      analyzer.registerPrivReq(new PrivilegeRequestBuilder()
+          .onDb(database_).allOf(Privilege.REFRESH).toRequest());
     } else {
-      analyzer.registerPrivReq(new PrivilegeRequest(Privilege.ALL));
+      analyzer.registerPrivReq(new PrivilegeRequest(Privilege.REFRESH));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
index 43e86cf..b6fc299 100644
--- a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
+++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
@@ -22,12 +22,12 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.lang.reflect.ConstructorUtils;
+import org.apache.impala.authorization.Privilege.SentryAction;
 import org.apache.impala.catalog.AuthorizationException;
 import org.apache.impala.catalog.AuthorizationPolicy;
 import org.apache.impala.common.InternalException;
 import org.apache.sentry.core.common.ActiveRoleSet;
 import org.apache.sentry.core.common.Subject;
-import org.apache.sentry.core.model.db.DBModelAction;
 import org.apache.sentry.core.model.db.DBModelAuthorizable;
 import org.apache.sentry.policy.db.SimpleDBPolicyEngine;
 import org.apache.sentry.provider.cache.SimpleCacheProviderBackend;
@@ -137,6 +137,11 @@ public class AuthorizationChecker {
         throw new AuthorizationException(String.format(
             "User '%s' does not have privileges to access: %s",
             user.getName(), privilegeRequest.getName()));
+      } else if (privilege == Privilege.REFRESH) {
+          throw new AuthorizationException(String.format(
+              "User '%s' does not have privileges to execute " +
+              "'INVALIDATE METADATA/REFRESH' on: %s", user.getName(),
+              privilegeRequest.getName()));
       } else {
         throw new AuthorizationException(String.format(
             "User '%s' does not have privileges to execute '%s' on: %s",
@@ -160,7 +165,7 @@ public class AuthorizationChecker {
       return true;
     }
 
-    EnumSet<DBModelAction> actions = request.getPrivilege().getHiveActions();
+    EnumSet<SentryAction> actions = request.getPrivilege().getSentryActions();
 
     List<DBModelAuthorizable> authorizeables = Lists.newArrayList(
         server_.getHiveAuthorizeableHierarchy());
@@ -172,7 +177,7 @@ public class AuthorizationChecker {
     // The Hive Access API does not currently provide a way to check if the user
     // has any privileges on a given resource.
     if (request.getPrivilege().getAnyOf()) {
-      for (DBModelAction action: actions) {
+      for (SentryAction action: actions) {
         if (provider_.hasAccess(new Subject(user.getShortName()), authorizeables,
             EnumSet.of(action), ActiveRoleSet.ALL)) {
           return true;

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/main/java/org/apache/impala/authorization/Privilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/Privilege.java b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
index 453558b..f82008c 100644
--- a/fe/src/main/java/org/apache/impala/authorization/Privilege.java
+++ b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
@@ -19,45 +19,67 @@ package org.apache.impala.authorization;
 
 import java.util.EnumSet;
 
-import org.apache.sentry.core.model.db.DBModelAction;
+import org.apache.sentry.core.common.Action;
 
 /**
- * Maps an Impala Privilege to one or more Hive Access "Actions".
+ * Maps an Impala Privilege to one or more Sentry "Actions".
  */
 public enum Privilege {
-  ALL(DBModelAction.ALL, false),
-  ALTER(DBModelAction.ALL, false),
-  DROP(DBModelAction.ALL, false),
-  CREATE(DBModelAction.ALL, false),
-  INSERT(DBModelAction.INSERT, false),
-  SELECT(DBModelAction.SELECT, false),
+  ALL(SentryAction.ALL, false),
+  ALTER(SentryAction.ALL, false),
+  DROP(SentryAction.ALL, false),
+  CREATE(SentryAction.ALL, false),
+  INSERT(SentryAction.INSERT, false),
+  SELECT(SentryAction.SELECT, false),
+  REFRESH(SentryAction.REFRESH, false),
   // Privileges required to view metadata on a server object.
-  VIEW_METADATA(EnumSet.of(DBModelAction.INSERT, DBModelAction.SELECT), true),
+  VIEW_METADATA(EnumSet.of(SentryAction.INSERT, SentryAction.SELECT,
+      SentryAction.REFRESH), true),
   // Special privilege that is used to determine if the user has any valid privileges
   // on a target object.
-  ANY(EnumSet.allOf(DBModelAction.class), true),
+  ANY(EnumSet.allOf(SentryAction.class), true),
   ;
 
-  private final EnumSet<DBModelAction> actions;
+  private final EnumSet<SentryAction> actions;
 
   // Determines whether to check if the user has ANY the privileges defined in the
   // actions list or whether to check if the user has ALL of the privileges in the
   // actions list.
   private final boolean anyOf_;
 
-  private Privilege(EnumSet<DBModelAction> actions, boolean anyOf) {
+  /**
+   * This enum provides a list of Sentry actions used in Impala.
+   */
+  public enum SentryAction implements Action {
+    SELECT("select"),
+    INSERT("insert"),
+    REFRESH("refresh"),
+    ALL("*");
+
+    private final String value;
+
+    SentryAction(String value) {
+      this.value = value;
+    }
+
+    public String getValue() {
+      return value;
+    }
+  }
+
+  private Privilege(EnumSet<SentryAction> actions, boolean anyOf) {
     this.actions = actions;
     this.anyOf_ = anyOf;
   }
 
-  private Privilege(DBModelAction action, boolean anyOf) {
+  private Privilege(SentryAction action, boolean anyOf) {
     this(EnumSet.of(action), anyOf);
   }
 
   /*
-   * Returns the set of Hive Access Actions mapping to this Privilege.
+   * Returns the set of Sentry Access Actions mapping to this Privilege.
    */
-  public EnumSet<DBModelAction> getHiveActions() {
+  public EnumSet<SentryAction> getSentryActions() {
     return actions;
   }
 

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index ddb95f1..f749e1f 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -165,7 +165,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL' privilege may be applied at SERVER scope in privilege spec.");
+          "Only 'ALL' or 'REFRESH' privilege may be applied at SERVER scope " +
+          "in privilege spec.");
       AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -180,7 +181,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL' privilege may be applied at SERVER scope in privilege spec.");
+          "Only 'ALL' or 'REFRESH' privilege may be applied at SERVER scope " +
+          "in privilege spec.");
       AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -219,6 +221,18 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
           "functional.does_not_exist %s myrole", formatArgs), "Error setting " +
           "privileges for table 'functional.does_not_exist'. Verify that the table " +
           "exists and that you have permissions to issue a GRANT/REVOKE statement.");
+
+      // REFRESH privilege
+      AnalyzesOk(String.format(
+          "%s REFRESH ON TABLE functional.alltypes %s myrole", formatArgs));
+      AnalyzesOk(String.format(
+          "%s REFRESH ON DATABASE functional %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s REFRESH ON SERVER %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s REFRESH ON SERVER server1 %s myrole",
+          formatArgs));
+      AnalysisError(String.format(
+          "%s REFRESH ON URI 'hdfs:////abc//123' %s myrole", formatArgs),
+          "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
     }
 
     AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index db31eaf..a309880 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -80,9 +80,9 @@ public class AuthorizationTest extends FrontendTestBase {
   //   ALL permission on 'tpch' database and 'newdb' database
   //   ALL permission on 'functional_seq_snap' database
   //   SELECT permissions on all tables in 'tpcds' database
-  //   SELECT permissions on 'functional.alltypesagg' (no INSERT permissions)
+  //   SELECT, REFRESH permissions on 'functional.alltypesagg' (no INSERT permissions)
   //   SELECT permissions on 'functional.complex_view' (no INSERT permissions)
-  //   SELECT permissions on 'functional.view_view' (no INSERT permissions)
+  //   SELECT, REFRESH permissions on 'functional.view_view' (no INSERT permissions)
   //   SELECT permissions on columns ('id', 'int_col', and 'year') on
   //   'functional.alltypessmall' (no SELECT permissions on 'functional.alltypessmall')
   //   SELECT permissions on columns ('id', 'int_struct_col', 'struct_array_col',
@@ -96,6 +96,7 @@ public class AuthorizationTest extends FrontendTestBase {
   //   No permissions on database 'functional_rc'
   //   Only column level permissions in 'functional_avro':
   //     SELECT permissions on columns ('id') on 'functional_avro.alltypessmall'
+  //   REFRESH permissions on 'functional_text_lzo' database
   public final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini";
   public final static User USER = new User(System.getProperty("user.name"));
 
@@ -233,6 +234,42 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // refresh_functional_text_lzo
+    roleName = "refresh_functional_text_lzo";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.REFRESH,
+        TPrivilegeScope.DATABASE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional_text_lzo");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
+    // refresh_functional_alltypesagg
+    roleName = "refresh_functional_alltypesagg";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.REFRESH,
+        TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("alltypesagg");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
+    // refresh_functional_view_view
+    roleName = "refresh_functional_view_view";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.REFRESH,
+        TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("view_view");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // all newdb w/ all on URI
     roleName = "all_newdb";
     sentryService.createRole(USER, roleName, true);
@@ -795,45 +832,64 @@ public class AuthorizationTest extends FrontendTestBase {
 
   @Test
   public void TestResetMetadata() throws ImpalaException {
-    // Positive cases (user has privileges on these tables/views).
+    // Positive cases (user has REFRESH privilege on these tables/views).
     AuthzOk("invalidate metadata functional.alltypesagg");
     AuthzOk("refresh functional.alltypesagg");
     AuthzOk("invalidate metadata functional.view_view");
     AuthzOk("refresh functional.view_view");
     // Positive cases for checking refresh partition
     AuthzOk("refresh functional.alltypesagg partition (year=2010, month=1, day=1)");
-    AuthzOk("refresh functional.alltypes partition (year=2009, month=1)");
     AuthzOk("refresh functional_seq_snap.alltypes partition (year=2009, month=1)");
+    // User has REFRESH privilege on functional_text_lzo database, =
+    // but no privilege at the table level.
+    AuthzOk("invalidate metadata functional_text_lzo.alltypes");
+    AuthzOk("refresh functional_text_lzo.alltypes");
+    AuthzOk("refresh functions functional_text_lzo");
 
     AuthzError("invalidate metadata unknown_db.alltypessmall",
-        "User '%s' does not have privileges to access: unknown_db.alltypessmall");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: unknown_db.alltypessmall");
     AuthzError("invalidate metadata functional_seq.alltypessmall",
-        "User '%s' does not have privileges to access: functional_seq.alltypessmall");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional_seq.alltypessmall");
     AuthzError("invalidate metadata functional.alltypes_view",
-        "User '%s' does not have privileges to access: functional.alltypes_view");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypes_view");
     AuthzError("invalidate metadata functional.unknown_table",
-        "User '%s' does not have privileges to access: functional.unknown_table");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.unknown_table");
     AuthzError("invalidate metadata functional.alltypessmall",
-        "User '%s' does not have privileges to access: functional.alltypessmall");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypessmall");
     AuthzError("refresh functional.alltypessmall",
-        "User '%s' does not have privileges to access: functional.alltypessmall");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypessmall");
     AuthzError("refresh functional.alltypes_view",
-        "User '%s' does not have privileges to access: functional.alltypes_view");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypes_view");
     // Only column-level privileges on the table
-    AuthzError("invalidate metadata functional.alltypestiny", "User '%s' does not " +
-        "have privileges to access: functional.alltypestiny");
+    AuthzError("invalidate metadata functional.alltypestiny",
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypestiny");
     // Only column-level privileges on the table
-    AuthzError("refresh functional.alltypestiny", "User '%s' does not have " +
-        "privileges to access: functional.alltypestiny");
+    AuthzError("refresh functional.alltypestiny",
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional.alltypestiny");
 
     AuthzError("invalidate metadata",
-        "User '%s' does not have privileges to access: server");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: server");
     AuthzError(
         "refresh functional_rc.alltypesagg partition (year=2010, month=1, day=1)",
-        "User '%s' does not have privileges to access: functional_rc.alltypesagg");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional_rc.alltypesagg");
     AuthzError(
         "refresh functional_rc.alltypesagg partition (year=2010, month=1, day=9999)",
-        "User '%s' does not have privileges to access: functional_rc.alltypesagg");
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional_rc.alltypesagg");
+    AuthzError("refresh functions functional_rc",
+        "User '%s' does not have privileges to execute 'INVALIDATE METADATA/REFRESH' " +
+        "on: functional_rc");
 
     // TODO: Add test support for dynamically changing privileges for
     // file-based policy.
@@ -842,11 +898,35 @@ public class AuthorizationTest extends FrontendTestBase {
 
     try {
       sentryService.grantRoleToGroup(USER, "admin", USER.getName());
-      ((ImpaladTestCatalog) ctx_.catalog).reset();
+      ctx_.catalog.reset();
       AuthzOk("invalidate metadata");
+      AuthzOk("invalidate metadata functional.testtbl");
+      AuthzOk("refresh functional.testtbl");
+      AuthzOk("refresh functional.alltypesagg partition (year=2010, month=1, day=1)");
+      AuthzOk("refresh functions functional");
     } finally {
       sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
-      ((ImpaladTestCatalog) ctx_.catalog).reset();
+      ctx_.catalog.reset();
+    }
+
+    // User has REFRESH privilege on server.
+    String roleName = "refresh_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.REFRESH,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+      AuthzOk("invalidate metadata");
+      AuthzOk("invalidate metadata functional.testtbl");
+      AuthzOk("refresh functional.testtbl");
+      AuthzOk("refresh functional.alltypesagg partition (year=2010, month=1, day=1)");
+      AuthzOk("refresh functions functional");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
     }
   }
 
@@ -1443,6 +1523,8 @@ public class AuthorizationTest extends FrontendTestBase {
   @Test
   public void TestDescribeDb() throws ImpalaException {
     AuthzOk("describe database functional_seq_snap");
+    // User has REFRESH privilege on functional_text_lzo database.
+    AuthzOk("describe database functional_text_lzo");
 
     // Database doesn't exist.
     AuthzError("describe database nodb",
@@ -1454,6 +1536,7 @@ public class AuthorizationTest extends FrontendTestBase {
 
   @Test
   public void TestDescribe() throws ImpalaException {
+    // User has SELECT and REFRESH privileges on functional.alltypesagg table.
     AuthzOk("describe functional.alltypesagg");
     AuthzOk("describe functional.alltypes");
     AuthzOk("describe functional.complex_view");
@@ -1542,6 +1625,9 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("show databases");
     AuthzOk("show tables in _impala_builtins");
     AuthzOk("show functions in _impala_builtins");
+    // User has REFRESH privilege on functional_text_lzo database.
+    AuthzOk("show tables in functional_text_lzo");
+    AuthzOk("show functions in functional_text_lzo");
 
     // Database exists, user does not have access.
     AuthzError("show tables in functional_rc",
@@ -1565,6 +1651,7 @@ public class AuthorizationTest extends FrontendTestBase {
     // Show partitions and show table/column stats.
     String[] statsQuals = new String[] { "partitions", "table stats", "column stats" };
     for (String qual: statsQuals) {
+      // User has SELECT and REFRESH privileges on functional.alltypesagg table.
       AuthzOk(String.format("show %s functional.alltypesagg", qual));
       AuthzOk(String.format("show %s functional.alltypes", qual));
       // User does not have access to db/table.
@@ -1582,6 +1669,8 @@ public class AuthorizationTest extends FrontendTestBase {
     // Show files
     String[] partitions = new String[] { "", "partition(month=10, year=2010)" };
     for (String partition: partitions) {
+      // User has SELECT and REFRESH privileges on functional.alltypesagg table.
+      AuthzOk(String.format("show files in functional.alltypesagg %s", partition));
       AuthzOk(String.format("show files in functional.alltypes %s", partition));
       // User does not have access to db/table.
       AuthzError(String.format("show files in nodb.tbl %s", partition),
@@ -1601,7 +1690,8 @@ public class AuthorizationTest extends FrontendTestBase {
     // These are the only dbs that should show up because they are the only
     // dbs the user has any permissions on.
     List<String> expectedDbs = Lists.newArrayList("default", "functional",
-        "functional_avro", "functional_parquet", "functional_seq_snap", "tpcds", "tpch");
+        "functional_avro", "functional_parquet", "functional_seq_snap",
+        "functional_text_lzo", "tpcds", "tpch");
 
     List<Db> dbs = fe_.getDbs(PatternMatcher.createHivePatternMatcher("*"), USER);
     assertEquals(expectedDbs, extractDbNames(dbs));
@@ -1663,11 +1753,11 @@ public class AuthorizationTest extends FrontendTestBase {
 
   @Test
   public void TestShowCreateTable() throws ImpalaException {
+    // User has SELECT and REFRESH privileges functional.alltypesagg table.
     AuthzOk("show create table functional.alltypesagg");
     AuthzOk("show create table functional.alltypes");
     // Have permissions on view and underlying table.
     AuthzOk("show create table functional_seq_snap.alltypes_view");
-
     // Unqualified table name.
     AuthzError("show create table alltypes",
         "User '%s' does not have privileges to access: default.alltypes");
@@ -1764,7 +1854,8 @@ public class AuthorizationTest extends FrontendTestBase {
     req.get_schemas_req.setSchemaName("%");
     TResultSet resp = fe_.execHiveServer2MetadataOp(req);
     List<String> expectedDbs = Lists.newArrayList("default", "functional",
-        "functional_avro", "functional_parquet", "functional_seq_snap", "tpcds", "tpch");
+        "functional_avro", "functional_parquet", "functional_seq_snap",
+        "functional_text_lzo", "tpcds", "tpch");
     assertEquals(expectedDbs.size(), resp.rows.size());
     for (int i = 0; i < resp.rows.size(); ++i) {
       assertEquals(expectedDbs.get(i),

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
index b51d148..aefa8e2 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
@@ -3575,6 +3575,12 @@ public class ParserTest extends FrontendTestBase {
           formatStr));
       ParserError(String.format("%s SELECT (a, b) ON URI 'foo' %s myRole", formatStr));
 
+      // REFRESH privilege.
+      ParsesOk(String.format("%s REFRESH ON SERVER %s myRole", formatStr));
+      ParsesOk(String.format("%s REFRESH ON SERVER foo %s myRole", formatStr));
+      ParsesOk(String.format("%s REFRESH ON DATABASE foo %s myRole", formatStr));
+      ParsesOk(String.format("%s REFRESH ON TABLE foo %s myRole", formatStr));
+
       // Server scope does not accept a name.
       ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr));
       ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr));

http://git-wip-us.apache.org/repos/asf/impala/blob/f2a89249/fe/src/test/resources/authz-policy.ini.template
----------------------------------------------------------------------
diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template
index 18abdb6..f3c7c1f 100644
--- a/fe/src/test/resources/authz-policy.ini.template
+++ b/fe/src/test/resources/authz-policy.ini.template
@@ -24,7 +24,9 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\
           select_functional_alltypesagg, insert_functional_alltypes,\
           select_functional_complex_view, select_functional_view_view,\
           insert_parquet, new_table_uri, tpch_data_uri, select_column_level_functional,\
-          select_column_level_functional_avro, upper_case_uri
+          select_column_level_functional_avro, upper_case_uri,\
+          refresh_functional_text_lzo, refresh_functional_alltypesagg,\
+          refresh_functional_view_view
 auth_to_local_group = test_role
 server_admin = all_server
 
@@ -47,6 +49,11 @@ select_functional_complex_view =\
 select_functional_view_view =\
     server=server1->db=functional->table=view_view->action=select
 insert_parquet = server=server1->db=functional_parquet->table=*->action=insert
+refresh_functional_text_lzo = server=server1->db=functional_text_lzo->action=refresh
+refresh_functional_alltypesagg =\
+    server=server1->db=functional->table=alltypesagg->action=refresh
+refresh_functional_view_view =\
+    server=server1->db=functional->table=view_view->action=refresh
 select_column_level_functional =\
     server=server1->db=functional->table=alltypessmall->column=id->action=select,\
     server=server1->db=functional->table=alltypessmall->column=int_col->action=select,\


[7/7] impala git commit: IMPALA-6800: Add test cases for statements that require ALTER privilege

Posted by lv...@apache.org.
IMPALA-6800: Add test cases for statements that require ALTER privilege

Testing:
- Added new test cases
- Ran front-end tests

Change-Id: Ie9fc1249420771ee857259c01acc3f9e7c9ed383
Reviewed-on: http://gerrit.cloudera.org:8080/9905
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/9ecbb184
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/9ecbb184
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/9ecbb184

Branch: refs/heads/2.x
Commit: 9ecbb1846b2cc6d062106f86bb193a34f92536ef
Parents: 22b10ef
Author: Fredy wijaya <fw...@cloudera.com>
Authored: Tue Apr 3 09:43:18 2018 -0700
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 .../java/org/apache/impala/analysis/AuthorizationTest.java     | 4 ++++
 fe/src/test/java/org/apache/impala/analysis/ParserTest.java    | 6 ++++++
 2 files changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/9ecbb184/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index ef6897c..ceb58c3 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -1642,6 +1642,8 @@ public class AuthorizationTest extends FrontendTestBase {
   @Test
   public void TestComputeStatsTable() throws ImpalaException {
     AuthzOk("compute stats functional_seq_snap.alltypes");
+    // User has ALTER privilege on functional.alltypeserror table.
+    AuthzOk("compute stats functional.alltypeserror");
 
     AuthzError("compute stats functional.alltypes",
         "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
@@ -1656,6 +1658,8 @@ public class AuthorizationTest extends FrontendTestBase {
   @Test
   public void TestDropStats() throws ImpalaException {
     AuthzOk("drop stats functional_seq_snap.alltypes");
+    // User has ALTER privilege on functional.alltypeserror table.
+    AuthzOk("drop stats functional.alltypeserror");
 
     AuthzError("drop stats functional.alltypes",
         "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");

http://git-wip-us.apache.org/repos/asf/impala/blob/9ecbb184/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
index e61266e..3eab55e 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
@@ -3586,6 +3586,12 @@ public class ParserTest extends FrontendTestBase {
       ParsesOk(String.format("%s CREATE ON SERVER foo %s myRole", formatStr));
       ParsesOk(String.format("%s CREATE ON DATABASE foo %s myRole", formatStr));
 
+      // ALTER privilege.
+      ParsesOk(String.format("%s ALTER ON SERVER %s myRole", formatStr));
+      ParsesOk(String.format("%s ALTER ON SERVER foo %s myRole", formatStr));
+      ParsesOk(String.format("%s ALTER ON DATABASE foo %s myRole", formatStr));
+      ParsesOk(String.format("%s ALTER ON TABLE foo %s myRole", formatStr));
+
       // Server scope does not accept a name.
       ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr));
       ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr));


[2/7] impala git commit: IMPALA-6650: Add fine-grained DROP privilege

Posted by lv...@apache.org.
IMPALA-6650: Add fine-grained DROP privilege

Add support for executing DROP statements by granting DROP privilege.

These are the new GRANT/REVOKE statements introduced at server,
database, and table scopes.

GRANT DROP on SERVER svr TO ROLE testrole;
GRANT DROP on DATABASE db TO ROLE testrole;
GRANT DROP on TABLE tbl TO ROLE testrole;

REVOKE DROP on SERVER svr FROM ROLE testrole;
REVOKE DROP on DATABASE db FROM ROLE testrole;
REVOKE DROP on TABLE tbl FROM ROLE testrole;

Testing:
- Added new front-end tests
- Ran front-end tests

Change-Id: Iea1dfb0b117cb1725e9656b9a79a9aebee82b5e4
Reviewed-on: http://gerrit.cloudera.org:8080/9911
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/d33ba936
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/d33ba936
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/d33ba936

Branch: refs/heads/2.x
Commit: d33ba936e89dbe8af2a3a5f2bf810a3afe18d53d
Parents: 9ecbb18
Author: Fredy Wijaya <fw...@cloudera.com>
Authored: Tue Apr 3 10:58:23 2018 -0500
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 common/thrift/CatalogObjects.thrift             |   3 +-
 fe/.gitignore                                   |   3 +
 fe/src/main/cup/sql-parser.cup                  |   2 +
 .../impala/analysis/DropFunctionStmt.java       |   7 +-
 .../apache/impala/analysis/PrivilegeSpec.java   |   7 +-
 .../authorization/AuthorizationChecker.java     |   6 +-
 .../apache/impala/authorization/Privilege.java  |   3 +-
 .../impala/analysis/AnalyzeAuthStmtsTest.java   |  18 ++-
 .../impala/analysis/AuthorizationTest.java      | 124 +++++++++++++++++--
 .../org/apache/impala/analysis/ParserTest.java  |   6 +
 fe/src/test/resources/authz-policy.ini.template |   8 +-
 11 files changed, 157 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/common/thrift/CatalogObjects.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift
index f6f1865..0f71f5f 100644
--- a/common/thrift/CatalogObjects.thrift
+++ b/common/thrift/CatalogObjects.thrift
@@ -472,7 +472,8 @@ enum TPrivilegeLevel {
   SELECT,
   REFRESH,
   CREATE,
-  ALTER
+  ALTER,
+  DROP
 }
 
 // Represents a privilege in an authorization policy. Privileges contain the level

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/.gitignore
----------------------------------------------------------------------
diff --git a/fe/.gitignore b/fe/.gitignore
index 6a1675d..11a5e9d 100644
--- a/fe/.gitignore
+++ b/fe/.gitignore
@@ -33,6 +33,9 @@ src/test/resources/authz-policy.ini
 # Generated minicluster config
 src/test/resources/minicluster-conf.xml
 
+# Generated hive-log4j2.properties file
+src/test/resources/hive-log4j2.properties
+
 # Generated thrift files
 generated-sources
 

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/main/cup/sql-parser.cup
----------------------------------------------------------------------
diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup
index 96bdb1d..f2d7cef 100644
--- a/fe/src/main/cup/sql-parser.cup
+++ b/fe/src/main/cup/sql-parser.cup
@@ -966,6 +966,8 @@ privilege ::=
   {: RESULT = TPrivilegeLevel.CREATE; :}
   | KW_ALTER
   {: RESULT = TPrivilegeLevel.ALTER; :}
+  | KW_DROP
+  {: RESULT = TPrivilegeLevel.DROP; :}
   | KW_ALL
   {: RESULT = TPrivilegeLevel.ALL; :}
   ;

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
index 1a533d1..2784aaf 100644
--- a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java
@@ -85,13 +85,10 @@ public class DropFunctionStmt extends StatementBase {
           false);
     }
 
-    // For now, if authorization is enabled, the user needs ALL on the server
-    // to drop functions.
-    // TODO: this is not the right granularity but acceptable for now.
     analyzer.registerPrivReq(new PrivilegeRequest(
-        new AuthorizeableFn(desc_.dbName(), desc_.signatureString()), Privilege.ALL));
+        new AuthorizeableFn(desc_.dbName(), desc_.signatureString()), Privilege.DROP));
 
-    Db db =  analyzer.getDb(desc_.dbName(), Privilege.DROP, false);
+    Db db =  analyzer.getDb(desc_.dbName(), false);
     if (db == null && !ifExists_) {
       throw new AnalysisException(Analyzer.DB_DOES_NOT_EXIST_ERROR_MSG + desc_.dbName());
     }

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index b2652cc..ec292a2 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -191,9 +191,10 @@ public class PrivilegeSpec implements ParseNode {
         if (privilegeLevel_ != TPrivilegeLevel.ALL &&
             privilegeLevel_ != TPrivilegeLevel.REFRESH &&
             privilegeLevel_ != TPrivilegeLevel.CREATE &&
-            privilegeLevel_ != TPrivilegeLevel.ALTER) {
-          throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' " +
-              "privilege may be applied at SERVER scope in privilege spec.");
+            privilegeLevel_ != TPrivilegeLevel.ALTER &&
+            privilegeLevel_ != TPrivilegeLevel.DROP) {
+          throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or " +
+              "'DROP' privilege may be applied at SERVER scope in privilege spec.");
         }
         break;
       case DATABASE:

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
index 04ac4ef..ee29c79 100644
--- a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
+++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
@@ -125,13 +125,13 @@ public class AuthorizationChecker {
     Preconditions.checkNotNull(privilegeRequest);
 
     if (!hasAccess(user, privilegeRequest)) {
+      Privilege privilege = privilegeRequest.getPrivilege();
       if (privilegeRequest.getAuthorizeable() instanceof AuthorizeableFn) {
         throw new AuthorizationException(String.format(
-            "User '%s' does not have privileges to CREATE/DROP functions in: %s",
-            user.getName(), privilegeRequest.getName()));
+            "User '%s' does not have privileges to %s functions in: %s",
+            user.getName(), privilege, privilegeRequest.getName()));
       }
 
-      Privilege privilege = privilegeRequest.getPrivilege();
       if (EnumSet.of(Privilege.ANY, Privilege.ALL, Privilege.VIEW_METADATA)
           .contains(privilege)) {
         throw new AuthorizationException(String.format(

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/main/java/org/apache/impala/authorization/Privilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/Privilege.java b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
index 558e4bd..59cc8d3 100644
--- a/fe/src/main/java/org/apache/impala/authorization/Privilege.java
+++ b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
@@ -27,7 +27,7 @@ import org.apache.sentry.core.common.Action;
 public enum Privilege {
   ALL(SentryAction.ALL, false),
   ALTER(SentryAction.ALTER, false),
-  DROP(SentryAction.ALL, false),
+  DROP(SentryAction.DROP, false),
   CREATE(SentryAction.CREATE, false),
   INSERT(SentryAction.INSERT, false),
   SELECT(SentryAction.SELECT, false),
@@ -56,6 +56,7 @@ public enum Privilege {
     REFRESH("refresh"),
     CREATE("create"),
     ALTER("alter"),
+    DROP("drop"),
     ALL("*");
 
     private final String value;

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index d1eae40..c56102f 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -165,8 +165,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " +
-          "SERVER scope in privilege spec.");
+          "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " +
+          "applied at SERVER scope in privilege spec.");
       AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -181,8 +181,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " +
-          "SERVER scope in privilege spec.");
+          "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " +
+          "applied at SERVER scope in privilege spec.");
       AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -255,6 +255,16 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalysisError(String.format(
           "%s ALTER ON URI 'hdfs:////abc/123' %s myrole", formatArgs),
           "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
+
+      // DROP privilege
+      AnalyzesOk(String.format("%s DROP ON SERVER %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s DROP ON SERVER server1 %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s DROP ON DATABASE functional %s myrole", formatArgs));
+      AnalyzesOk(String.format(
+          "%s DROP ON TABLE functional.alltypes %s myrole", formatArgs));
+      AnalysisError(String.format(
+          "%s DROP ON URI 'hdfs:////abc/123' %s myrole", formatArgs),
+          "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
     }
 
     AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index ceb58c3..4dba03b 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -40,6 +40,7 @@ import org.apache.impala.catalog.AuthorizationException;
 import org.apache.impala.catalog.Db;
 import org.apache.impala.catalog.ImpaladCatalog;
 import org.apache.impala.catalog.ScalarFunction;
+import org.apache.impala.catalog.ScalarType;
 import org.apache.impala.catalog.Type;
 import org.apache.impala.common.AnalysisException;
 import org.apache.impala.common.FrontendTestBase;
@@ -80,11 +81,11 @@ public class AuthorizationTest extends FrontendTestBase {
   //   ALL permission on 'tpch' database and 'newdb' database
   //   ALL permission on 'functional_seq_snap' database
   //   SELECT permissions on all tables in 'tpcds' database
-  //   SELECT, REFRESH permissions on 'functional.alltypesagg' (no INSERT permissions)
+  //   SELECT, REFRESH, DROP permissions on 'functional.alltypesagg'
   //   ALTER permissions on 'functional.alltypeserror'
-  //   SELECT permissions on 'functional.complex_view' (no INSERT permissions)
-  //   SELECT, REFRESH permissions on 'functional.view_view' (no INSERT permissions)
-  //   ALTER permission on 'functional.alltypes_view'
+  //   SELECT permissions on 'functional.complex_view'
+  //   SELECT, REFRESH permissions on 'functional.view_view'
+  //   ALTER, DROP permissions on 'functional.alltypes_view'
   //   SELECT permissions on columns ('id', 'int_col', and 'year') on
   //   'functional.alltypessmall' (no SELECT permissions on 'functional.alltypessmall')
   //   SELECT permissions on columns ('id', 'int_struct_col', 'struct_array_col',
@@ -98,7 +99,7 @@ public class AuthorizationTest extends FrontendTestBase {
   //   No permissions on database 'functional_rc'
   //   Only column level permissions in 'functional_avro':
   //     SELECT permissions on columns ('id') on 'functional_avro.alltypessmall'
-  //   REFRESH, INSERT, CREATE, ALTER permissions on 'functional_text_lzo' database
+  //   REFRESH, INSERT, CREATE, ALTER, DROP permissions on 'functional_text_lzo' database
   public final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini";
   public final static User USER = new User(System.getProperty("user.name"));
 
@@ -260,6 +261,18 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name("alltypesagg");
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // drop_functional_alltypesagg
+    roleName = "drop_functional_alltypesagg";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.DROP,
+        TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("alltypesagg");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // refresh_functional_view_view
     roleName = "refresh_functional_view_view";
     sentryService.createRole(USER, roleName, true);
@@ -272,6 +285,18 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name("view_view");
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // drop_functional_alltypes_view
+    roleName = "drop_functional_alltypes_view";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.DROP,
+        TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("alltypes_view");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // insert_functional_text_lzo
     roleName = "insert_functional_text_lzo";
     sentryService.createRole(USER, roleName, true);
@@ -308,6 +333,18 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // drop_functional_text_lzo
+    roleName = "drop_functional_text_lzo";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.DROP, TPrivilegeScope.DATABASE,
+        false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional_text_lzo");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // alter_functional_alltypeserror
     roleName = "alter_functional_alltypeserror";
     sentryService.createRole(USER, roleName, true);
@@ -1248,6 +1285,15 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("drop database if exists newdb");
     AuthzOk("drop database if exists newdb cascade");
     AuthzOk("drop database if exists newdb restrict");
+
+    // User has DROP privilege on functional_text_lzo database.
+    AuthzOk("drop database functional_text_lzo");
+    AuthzOk("drop database functional_text_lzo cascade");
+    AuthzOk("drop database functional_text_lzo restrict");
+    AuthzOk("drop database if exists functional_text_lzo");
+    AuthzOk("drop database if exists functional_text_lzo cascade");
+    AuthzOk("drop database if exists functional_text_lzo restrict");
+
     // User has permission, database does not exists, IF EXISTS not specified.
     try {
       AuthzOk("drop database newdb");
@@ -1298,6 +1344,9 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("drop table tpch.lineitem");
     AuthzOk("drop table if exists tpch.lineitem");
 
+    // User has DROP privilege on functional.alltypesagg table.
+    AuthzOk("drop table functional.alltypesagg");
+
     // Drop table (user does not have permission).
     AuthzError("drop table functional.alltypes",
         "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
@@ -1334,10 +1383,13 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("drop view functional_seq_snap.alltypes_view");
     AuthzOk("drop view if exists functional_seq_snap.alltypes_view");
 
-    // Drop view (user does not have permission).
-    AuthzError("drop view functional.alltypes_view",
+    // User has DROP privilege on functional.alltypes_view view.
+    AuthzOk("drop view functional.alltypes_view");
+
+    // User does not have DROP privilege on functional.alltypes_view_sub view.
+    AuthzError("drop view functional.alltypes_view_sub",
         "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
-    AuthzError("drop view if exists functional.alltypes_view",
+    AuthzError("drop view if exists functional.alltypes_view_sub",
         "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
 
     // Drop view with unqualified table name.
@@ -2207,7 +2259,7 @@ public class AuthorizationTest extends FrontendTestBase {
 
     AuthzError(ctx, "create function f() returns int location " +
         "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-        "User '%s' does not have privileges to CREATE/DROP functions in: default.f()");
+        "User '%s' does not have privileges to CREATE functions in: default.f()");
 
     // User has ALL privilege on tpch database and ALL privilege on
     // /test-warehouse/libTestUdfs.so URI.
@@ -2216,13 +2268,25 @@ public class AuthorizationTest extends FrontendTestBase {
 
     AuthzError(ctx, "create function notdb.f() returns int location " +
         "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
-        "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()");
+        "User '%s' does not have privileges to CREATE functions in: notdb.f()");
+
+    // User has DROP privilege on functional_text_lzo database.
+    try {
+      ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional_text_lzo",
+          "f", new ArrayList<Type>(), Type.INT, "/dummy", "dummy.class", null,
+          null, TFunctionBinaryType.NATIVE));
+      AuthzOk("drop function functional_text_lzo.f()");
+    } finally {
+      ctx_.catalog.removeFunction(ScalarFunction.createForTesting("functional_text_lzo",
+          "f", new ArrayList<Type>(), Type.INT, "/dummy", "dummy.class", null,
+          null, TFunctionBinaryType.NATIVE));
+    }
 
     AuthzError(ctx, "drop function if exists f()",
-        "User '%s' does not have privileges to CREATE/DROP functions in: default.f()");
+        "User '%s' does not have privileges to DROP functions in: default.f()");
 
     AuthzError(ctx, "drop function notdb.f()",
-        "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()");
+        "User '%s' does not have privileges to DROP functions in: notdb.f()");
 
     // User does not have ALL privilege on SERVER and tries to create a function with
     // the same name as the built-in function.
@@ -2519,6 +2583,42 @@ public class AuthorizationTest extends FrontendTestBase {
     }
   }
 
+  @Test
+  public void TestServerLevelDrop() throws ImpalaException {
+    // TODO: Add test support for dynamically changing privileges for
+    // file-based policy.
+    if (ctx_.authzConfig.isFileBasedPolicy()) return;
+
+    SentryPolicyService sentryService =
+        new SentryPolicyService(ctx_.authzConfig.getSentryConfig());
+
+    // User has DROP privilege on server.
+    String roleName = "drop_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.DROP,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+
+      AuthzOk("drop database functional");
+      AuthzOk("drop table functional.alltypes");
+      AuthzOk("drop view functional.alltypes_view_sub");
+      ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional",
+          "f", new ArrayList<Type>(), Type.INT, "/dummy", "dummy.class", null,
+          null, TFunctionBinaryType.NATIVE));
+      AuthzOk("drop function functional.f()");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
+      ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional",
+          "f", new ArrayList<Type>(), Type.INT, "/dummy", "dummy.class", null,
+          null, TFunctionBinaryType.NATIVE));
+    }
+  }
+
   private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user)
       throws ImpalaException {
     Frontend fe = new Frontend(authzConfig, ctx_.catalog);

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
index 3eab55e..ab0eb78 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
@@ -3592,6 +3592,12 @@ public class ParserTest extends FrontendTestBase {
       ParsesOk(String.format("%s ALTER ON DATABASE foo %s myRole", formatStr));
       ParsesOk(String.format("%s ALTER ON TABLE foo %s myRole", formatStr));
 
+      // DROP privilege.
+      ParsesOk(String.format("%s DROP ON SERVER %s myRole", formatStr));
+      ParsesOk(String.format("%s DROP ON SERVER foo %s myRole", formatStr));
+      ParsesOk(String.format("%s DROP ON DATABASE foo %s myRole", formatStr));
+      ParsesOk(String.format("%s DROP ON TABLE foo %s myRole", formatStr));
+
       // Server scope does not accept a name.
       ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr));
       ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr));

http://git-wip-us.apache.org/repos/asf/impala/blob/d33ba936/fe/src/test/resources/authz-policy.ini.template
----------------------------------------------------------------------
diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template
index 82b1060..26ed70b 100644
--- a/fe/src/test/resources/authz-policy.ini.template
+++ b/fe/src/test/resources/authz-policy.ini.template
@@ -29,7 +29,8 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\
           refresh_functional_view_view, insert_functional_text_lzo,\
           create_functional_text_lzo, alter_functional_text_lzo,\
           alter_functional_alltypeserror, alter_functional_alltypes_view,\
-          libtestudfs_uri
+          libtestudfs_uri, drop_functional_text_lzo, drop_functional_alltypesagg,\
+          drop_functional_alltypes_view
 auth_to_local_group = test_role
 server_admin = all_server
 
@@ -55,15 +56,20 @@ insert_parquet = server=server1->db=functional_parquet->table=*->action=insert
 refresh_functional_text_lzo = server=server1->db=functional_text_lzo->action=refresh
 refresh_functional_alltypesagg =\
     server=server1->db=functional->table=alltypesagg->action=refresh
+drop_functional_alltypesagg =\
+    server=server1->db=functional->table=alltypesagg->action=drop
 alter_functional_alltypeserror =\
     server=server1->db=functional->table=alltypeserror->action=alter
 refresh_functional_view_view =\
     server=server1->db=functional->table=view_view->action=refresh
+drop_functional_alltypes_view =\
+    server=server1->db=functional->table=alltypes_view->action=drop
 alter_functional_alltypes_view =\
     server=server1->db=functional->table=alltypes_view->action=alter
 insert_functional_text_lzo = server=server1->db=functional_text_lzo->action=insert
 create_functional_text_lzo = server=server1->db=functional_text_lzo->action=create
 alter_functionl_text_lzo = server=server1->db=functional_text_lzo->action=alter
+drop_functional_text_lzo = server=server1->db=functional_text_lzo->action=drop
 select_column_level_functional =\
     server=server1->db=functional->table=alltypessmall->column=id->action=select,\
     server=server1->db=functional->table=alltypessmall->column=int_col->action=select,\


[6/7] impala git commit: IMPALA-6804: Allow SELECT and INSERT privileges on SERVER

Posted by lv...@apache.org.
IMPALA-6804: Allow SELECT and INSERT privileges on SERVER

This change add the last two privileges at the SERVER level.

GRANT SELECT ON SERVER TO ROLE test_role;
REVOKE SELECT ON SERVER FROM ROLE test_role;
GRANT INSERT ON SERVER TO ROLE test_role
REVOKE INSERT ON SERVER FROM ROLE test_role

Testing:
Added tests to cover server level select and insert.
Ran all front-end tests.

Change-Id: If6510b4d54c9902029a357f1aebb2570cd75855d
Reviewed-on: http://gerrit.cloudera.org:8080/9972
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins <im...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/c226f0e8
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/c226f0e8
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/c226f0e8

Branch: refs/heads/2.x
Commit: c226f0e82e5a03d539f8b0bbe1785b383fc0e0f4
Parents: d33ba93
Author: Adam Holley <gi...@holleyism.com>
Authored: Tue Apr 10 11:29:55 2018 -0500
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 .../apache/impala/analysis/PrivilegeSpec.java   |   8 -
 .../impala/analysis/AnalyzeAuthStmtsTest.java   |   8 +-
 .../impala/analysis/AuthorizationTest.java      | 192 +++++++++++++++++--
 3 files changed, 179 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/c226f0e8/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index ec292a2..d848383 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -188,14 +188,6 @@ public class PrivilegeSpec implements ParseNode {
 
     switch (scope_) {
       case SERVER:
-        if (privilegeLevel_ != TPrivilegeLevel.ALL &&
-            privilegeLevel_ != TPrivilegeLevel.REFRESH &&
-            privilegeLevel_ != TPrivilegeLevel.CREATE &&
-            privilegeLevel_ != TPrivilegeLevel.ALTER &&
-            privilegeLevel_ != TPrivilegeLevel.DROP) {
-          throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or " +
-              "'DROP' privilege may be applied at SERVER scope in privilege spec.");
-        }
         break;
       case DATABASE:
         Preconditions.checkState(!Strings.isNullOrEmpty(dbName_));

http://git-wip-us.apache.org/repos/asf/impala/blob/c226f0e8/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index c56102f..2741e5d 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -164,9 +164,7 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
           formatArgs));
       AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole",
           formatArgs));
-      AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " +
-          "applied at SERVER scope in privilege spec.");
+      AnalyzesOk(String.format("%s INSERT ON SERVER %s myrole", formatArgs));
       AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -180,9 +178,7 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
           "%s SELECT ON TABLE functional_kudu.alltypessmall %s myrole", formatArgs));
       AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole",
           formatArgs));
-      AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " +
-          "applied at SERVER scope in privilege spec.");
+      AnalyzesOk(String.format("%s SELECT ON SERVER %s myrole", formatArgs));
       AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");

http://git-wip-us.apache.org/repos/asf/impala/blob/c226f0e8/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index 4dba03b..c82b4c8 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -605,9 +605,9 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("select * from functional.view_view");
 
     // User does not have SELECT privileges on this view.
-    AuthzError("select * from functional.complex_view_sub",
+    AuthzError("select * from functional.alltypes_view",
         "User '%s' does not have privileges to execute 'SELECT' on: " +
-        "functional.complex_view_sub");
+        "functional.alltypes_view");
 
     // User has SELECT privileges on the view and the join table.
     AuthzOk("select a.id from functional.view_view a "
@@ -641,11 +641,6 @@ public class AuthorizationTest extends FrontendTestBase {
         "User '%s' does not have privileges to execute 'SELECT' on: " +
         "functional.alltypes");
 
-    // Select with no privileges on view.
-    AuthzError("select * from functional.complex_view_sub",
-        "User '%s' does not have privileges to execute 'SELECT' on: " +
-        "functional.complex_view_sub");
-
     // Select without referencing a column.
     AuthzError("select 1 from functional.alltypes",
         "User '%s' does not have privileges to execute 'SELECT' on: " +
@@ -704,7 +699,7 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("select id, b.key from functional.allcomplextypes a, a.int_map_col b");
 
     // No SELECT privileges on 'alltypessmall'
-    AuthzError("select a.* from functional.alltypesagg cross join " +
+    AuthzError("select a.* from functional.alltypesagg a cross join " +
         "functional.alltypessmall b", "User '%s' does not have privileges to execute " +
         "'SELECT' on: functional.alltypessmall");
 
@@ -758,11 +753,15 @@ public class AuthorizationTest extends FrontendTestBase {
         "functional.alltypes");
 
     // User doesn't have permissions on source table within inline view.
-    AuthzError("insert into functional.alltypes " +
-        "select * from functional.alltypesagg a join (select * from " +
-        "functional_seq.alltypes) b on (a.int_col = b.int_col)",
-        "User '%s' does not have privileges to execute 'SELECT' on: " +
-        "functional_seq.alltypes");
+    AuthzError("insert into functional.alltypes partition (month, year) " +
+        "select id, bool_col, tinyint_col, smallint_col, a.int_col, bigint_col, " +
+        "float_col, a.double_col, a.date_string_col, a.string_col, a.timestamp_col, " +
+        "a.year, a.month " +
+        "from functional_rc.alltypesagg a " +
+        "join (select int_col, double_col, date_string_col, string_col, timestamp_col, " +
+        "year, month from functional_seq.alltypes) b " +
+        "on (a.int_col = b.int_col)", "User '%s' does " +
+        "not have privileges to execute 'SELECT' on: functional_rc.alltypesagg");
 
     // User doesn't have INSERT permissions on the target table but has sufficient SELECT
     // permissions on all the referenced columns of the source table
@@ -1764,8 +1763,8 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzError("describe formatted functional.alltypestiny",
         "User '%s' does not have privileges to access: functional.alltypestiny");
     // Insufficient privileges on table for nested column.
-    AuthzError("describe functional.complextypestbl.nested_struct",
-        "User '%s' does not have privileges to access: functional.complextypestbl");
+    AuthzError("describe functional.complextypes_fileformat.s",
+        "User '%s' does not have privileges to access: functional.complextypes_fileformat");
     // Insufficient privileges on view.
     AuthzError("describe functional.alltypes_view_sub",
         "User '%s' does not have privileges to access: functional.alltypes_view_sub");
@@ -2503,6 +2502,169 @@ public class AuthorizationTest extends FrontendTestBase {
   }
 
   @Test
+  public void TestServerLevelInsert() throws ImpalaException {
+    // TODO: Add test support for dynamically changing privileges for
+    // file-based policy.
+    if (ctx_.authzConfig.isFileBasedPolicy()) return;
+
+    SentryPolicyService sentryService =
+        new SentryPolicyService(ctx_.authzConfig.getSentryConfig());
+
+    // User has INSERT privilege on server.
+    String roleName = "insert_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.INSERT,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+      privilege = new TPrivilege ("", TPrivilegeLevel.SELECT, TPrivilegeScope.DATABASE,
+          false);
+      privilege.setServer_name("server1");
+      privilege.setDb_name("functional_rc");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+      privilege = new TPrivilege ("", TPrivilegeLevel.SELECT, TPrivilegeScope.DATABASE,
+          false);
+      privilege.setServer_name("server1");
+      privilege.setDb_name("functional_seq");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+
+      // Copied majority of INSERT tests that should fail from authorization and
+      // ensure they succeed here. Some tests that fail will fail here with
+      // AnalysisException and are covered elsewhere.
+
+      // User has SELECT permissions on source table.
+      AuthzOk("insert into functional.alltypes partition (month, year) " +
+              "select * from functional_rc.alltypes");
+
+      // Ensure INSERT at server does not allow other privileges
+      AuthzError("select * from functional.alltypes",
+          "User '%s' does not have privileges to execute 'SELECT' on: functional");
+      AuthzError("create table functional.new_table (i int)",
+          "User '%s' does not have privileges to execute 'CREATE' on: functional");
+      AuthzError("alter table functional.alltypes add columns (c1 int)",
+          "User '%s' does not have privileges to execute 'ALTER' on: " +
+          "functional.alltypes");
+      AuthzError("drop table functional.alltypes",
+          "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
+
+      // User has permissions on source table within inline view.
+      AuthzOk("insert into functional.alltypes partition (month, year) " +
+          "select id, bool_col, tinyint_col, smallint_col, a.int_col, bigint_col, " +
+          "float_col, a.double_col, a.date_string_col, a.string_col, a.timestamp_col, " +
+          "a.year, a.month from functional_rc.alltypesagg a " +
+          "join (select int_col, double_col, date_string_col, string_col, " +
+          "timestamp_col, year, month from functional_seq.alltypes) b " +
+          "on (a.int_col = b.int_col)");
+
+      // User has INSERT permissions on the target table and has sufficient SELECT
+      // permissions on all the referenced columns of the source table
+      AuthzOk("insert into functional.alltypestiny partition (month, year) " +
+          "select * from functional_rc.alltypestiny");
+
+      // User has INSERT permissions on target table and column-level
+      // permissions on the source table
+      AuthzOk("insert into functional.alltypes partition (month, year) " +
+          "select * from functional_rc.alltypessmall");
+
+      // Insert and Select allow view_metadata
+      AuthzOk("describe database functional_rc");
+      AuthzOk("describe functional.complextypes_fileformat.s");
+      AuthzOk("describe functional.alltypes_view_sub");
+      AuthzOk("describe functional_rc.alltypes");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
+    }
+  }
+
+  @Test
+  public void TestServerLevelSelect() throws ImpalaException {
+    // TODO: Add test support for dynamically changing privileges for
+    // file-based policy.
+    if (ctx_.authzConfig.isFileBasedPolicy()) return;
+
+    SentryPolicyService sentryService =
+        new SentryPolicyService(ctx_.authzConfig.getSentryConfig());
+
+    // User has SELECT privilege on server.
+    String roleName = "select_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.SELECT,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+
+      // Copied majority of SELECT tests that should fail from authorization and
+      // ensure they succeed here.
+      AuthzOk("select * from functional.alltypes_view_sub");
+      AuthzOk("select * from functional.alltypes");
+
+      // Ensure SELECT at server does not allow other privileges
+      AuthzError("insert into functional.alltypesagg select 1",
+          "User '%s' does not have privileges to execute 'INSERT' on: " +
+          "functional.alltypesagg");
+      AuthzError("create table functional.new_table (i int)",
+          "User '%s' does not have privileges to execute 'CREATE' on: functional");
+      AuthzError("alter table functional.alltypes add columns (c1 int)",
+          "User '%s' does not have privileges to execute 'ALTER' on: " +
+          "functional.alltypes");
+      AuthzError("drop table functional.alltypes",
+          "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
+
+      // User has SELECT privileges on the view, and has privileges
+      // to select join table.
+      AuthzOk("select a.id from functional.view_view a " +
+          "join functional.alltypes b ON (a.id = b.id)");
+
+      // User has SELECT privileges on the view which contains a subquery.
+      AuthzOk("select * from functional_rc.subquery_view");
+
+      // Constant select.
+      AuthzOk("select 1");
+
+      // Table within inline view is authorized properly.
+      AuthzOk("select a.* from (select * from functional.alltypes) a");
+
+      // SELECT privileges on all the columns of 'alltypessmall'
+      AuthzOk("select * from functional.alltypessmall");
+
+      // SELECT privileges on table 'alltypessmall'
+      AuthzOk("select count(*) from functional.alltypessmall");
+      AuthzOk("select 1 from functional.alltypessmall");
+
+      // SELECT privileges on column 'month'
+      AuthzOk("select id, int_col, year, month from functional.alltypessmall");
+
+      // SELECT privileges on 'int_array_col'
+      AuthzOk("select a.id, b.item from functional.allcomplextypes a, " +
+          "a.int_array_col b");
+
+      // SELECT privileges on 'alltypessmall'
+      AuthzOk("select a.* from functional.alltypesagg a cross join " +
+          "functional.alltypessmall b");
+
+      // Insert allows view_metadata
+      AuthzOk("describe database functional_rc");
+      AuthzOk("describe functional.complextypes_fileformat.s");
+      AuthzOk("describe functional.alltypes_view_sub");
+      AuthzOk("describe functional_rc.alltypes");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
+    }
+  }
+
+  @Test
   public void TestServerLevelCreate() throws ImpalaException {
     // TODO: Add test support for dynamically changing privileges for
     // file-based policy.


[5/7] impala git commit: IMPALA-6649: Add fine-grained ALTER privilege

Posted by lv...@apache.org.
IMPALA-6649: Add fine-grained ALTER privilege

Updated support and analysis files to provide ALTER privilege.

Example statements:
GRANT ALTER on SERVER svr TO ROLE testrole;
GRANT ALTER on DATABASE db TO ROLE testrole;
GRANT ALTER on TABLE tbl TO ROLE testrole;

REVOKE ALTER on SERVER svr FROM ROLE testrole;
REVOKE ALTER on DATABASE db FROM ROLE testrole;
REVOKE ALTER on TABLE tbl FROM ROLE testrole;

ALTER TABLE ... RENAME requires TABLE level privileges and
CREATE at the DATABASE level.

Tests:
Added ALTER tests to cover scope of existing ALTER tests but in
the context of only having ALTER privilege.
Ran all fe tests.

Change-Id: I0b25d10a8634829fbe90e308dfc7efc8182fef2d
Reviewed-on: http://gerrit.cloudera.org:8080/9805
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/22b10efe
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/22b10efe
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/22b10efe

Branch: refs/heads/2.x
Commit: 22b10efe0e09f3985349a203b9edb34b8d3e8c6d
Parents: 9f90a65
Author: Adam Holley <gi...@holleyism.com>
Authored: Mon Mar 26 13:40:05 2018 -0500
Committer: Fredy Wijaya <fw...@cloudera.com>
Committed: Wed Apr 25 13:22:15 2018 -0700

----------------------------------------------------------------------
 common/thrift/CatalogObjects.thrift             |   3 +-
 fe/src/main/cup/sql-parser.cup                  |   2 +
 .../apache/impala/analysis/PrivilegeSpec.java   |   7 +-
 .../apache/impala/authorization/Privilege.java  |   3 +-
 .../impala/analysis/AnalyzeAuthStmtsTest.java   |  18 ++-
 .../impala/analysis/AuthorizationTest.java      | 161 +++++++++++++++++--
 fe/src/test/resources/authz-policy.ini.template |   9 +-
 7 files changed, 184 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/common/thrift/CatalogObjects.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift
index 9cacd6e..f6f1865 100644
--- a/common/thrift/CatalogObjects.thrift
+++ b/common/thrift/CatalogObjects.thrift
@@ -471,7 +471,8 @@ enum TPrivilegeLevel {
   INSERT,
   SELECT,
   REFRESH,
-  CREATE
+  CREATE,
+  ALTER
 }
 
 // Represents a privilege in an authorization policy. Privileges contain the level

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/main/cup/sql-parser.cup
----------------------------------------------------------------------
diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup
index d6c219b..96bdb1d 100644
--- a/fe/src/main/cup/sql-parser.cup
+++ b/fe/src/main/cup/sql-parser.cup
@@ -964,6 +964,8 @@ privilege ::=
   {: RESULT = TPrivilegeLevel.REFRESH; :}
   | KW_CREATE
   {: RESULT = TPrivilegeLevel.CREATE; :}
+  | KW_ALTER
+  {: RESULT = TPrivilegeLevel.ALTER; :}
   | KW_ALL
   {: RESULT = TPrivilegeLevel.ALL; :}
   ;

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index fcece28..b2652cc 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -190,9 +190,10 @@ public class PrivilegeSpec implements ParseNode {
       case SERVER:
         if (privilegeLevel_ != TPrivilegeLevel.ALL &&
             privilegeLevel_ != TPrivilegeLevel.REFRESH &&
-            privilegeLevel_ != TPrivilegeLevel.CREATE) {
-          throw new AnalysisException("Only 'ALL', 'REFRESH', or 'CREATE' privilege " +
-              "may be applied at SERVER scope in privilege spec.");
+            privilegeLevel_ != TPrivilegeLevel.CREATE &&
+            privilegeLevel_ != TPrivilegeLevel.ALTER) {
+          throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' " +
+              "privilege may be applied at SERVER scope in privilege spec.");
         }
         break;
       case DATABASE:

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/main/java/org/apache/impala/authorization/Privilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/authorization/Privilege.java b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
index b6fa14c..558e4bd 100644
--- a/fe/src/main/java/org/apache/impala/authorization/Privilege.java
+++ b/fe/src/main/java/org/apache/impala/authorization/Privilege.java
@@ -26,7 +26,7 @@ import org.apache.sentry.core.common.Action;
  */
 public enum Privilege {
   ALL(SentryAction.ALL, false),
-  ALTER(SentryAction.ALL, false),
+  ALTER(SentryAction.ALTER, false),
   DROP(SentryAction.ALL, false),
   CREATE(SentryAction.CREATE, false),
   INSERT(SentryAction.INSERT, false),
@@ -55,6 +55,7 @@ public enum Privilege {
     INSERT("insert"),
     REFRESH("refresh"),
     CREATE("create"),
+    ALTER("alter"),
     ALL("*");
 
     private final String value;

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index 825ed35..d1eae40 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -165,8 +165,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', or 'CREATE' privilege may be applied at SERVER " +
-          "scope in privilege spec.");
+          "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " +
+          "SERVER scope in privilege spec.");
       AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -181,8 +181,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole",
           formatArgs));
       AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs),
-          "Only 'ALL', 'REFRESH', or 'CREATE' privilege may be applied at SERVER " +
-          "scope in privilege spec.");
+          "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " +
+          "SERVER scope in privilege spec.");
       AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole",
           formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " +
           "spec.");
@@ -245,6 +245,16 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest {
       AnalysisError(String.format(
           "%s CREATE ON URI 'hdfs:////abc//123' %s myrole", formatArgs),
           "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
+
+      // ALTER privilege
+      AnalyzesOk(String.format("%s ALTER ON SERVER %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s ALTER ON SERVER server1 %s myrole", formatArgs));
+      AnalyzesOk(String.format("%s ALTER ON DATABASE functional %s myrole", formatArgs));
+      AnalyzesOk(String.format(
+          "%s ALTER ON TABLE functional.alltypes %s myrole", formatArgs));
+      AnalysisError(String.format(
+          "%s ALTER ON URI 'hdfs:////abc/123' %s myrole", formatArgs),
+          "Only 'ALL' privilege may be applied at URI scope in privilege spec.");
     }
 
     AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
index 40865c8..ef6897c 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java
@@ -81,8 +81,10 @@ public class AuthorizationTest extends FrontendTestBase {
   //   ALL permission on 'functional_seq_snap' database
   //   SELECT permissions on all tables in 'tpcds' database
   //   SELECT, REFRESH permissions on 'functional.alltypesagg' (no INSERT permissions)
+  //   ALTER permissions on 'functional.alltypeserror'
   //   SELECT permissions on 'functional.complex_view' (no INSERT permissions)
   //   SELECT, REFRESH permissions on 'functional.view_view' (no INSERT permissions)
+  //   ALTER permission on 'functional.alltypes_view'
   //   SELECT permissions on columns ('id', 'int_col', and 'year') on
   //   'functional.alltypessmall' (no SELECT permissions on 'functional.alltypessmall')
   //   SELECT permissions on columns ('id', 'int_struct_col', 'struct_array_col',
@@ -96,7 +98,7 @@ public class AuthorizationTest extends FrontendTestBase {
   //   No permissions on database 'functional_rc'
   //   Only column level permissions in 'functional_avro':
   //     SELECT permissions on columns ('id') on 'functional_avro.alltypessmall'
-  //   REFRESH, INSERT, CREATE permissions on 'functional_text_lzo' database
+  //   REFRESH, INSERT, CREATE, ALTER permissions on 'functional_text_lzo' database
   public final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini";
   public final static User USER = new User(System.getProperty("user.name"));
 
@@ -104,8 +106,8 @@ public class AuthorizationTest extends FrontendTestBase {
   // column-level SELECT or INSERT permission. I.e. that should be returned by
   // 'SHOW TABLES'.
   private static final List<String> FUNCTIONAL_VISIBLE_TABLES = Lists.newArrayList(
-      "allcomplextypes", "alltypes", "alltypesagg", "alltypessmall", "alltypestiny",
-      "complex_view", "view_view");
+      "allcomplextypes", "alltypes", "alltypes_view", "alltypesagg", "alltypeserror",
+      "alltypessmall", "alltypestiny", "complex_view", "view_view");
 
   /**
    * Test context whose instances are used to parameterize this test.
@@ -294,6 +296,41 @@ public class AuthorizationTest extends FrontendTestBase {
     privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
     sentryService.grantRolePrivilege(USER, roleName, privilege);
 
+    // alter_functional_text_lzo
+    roleName = "alter_functional_text_lzo";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.ALTER, TPrivilegeScope.DATABASE,
+        false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional_text_lzo");
+    privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
+    // alter_functional_alltypeserror
+    roleName = "alter_functional_alltypeserror";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.ALTER, TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("alltypeserror");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
+    // alter_functional_alltypes_view
+    roleName = "alter_functional_alltypes_view";
+    sentryService.createRole(USER, roleName, true);
+    sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+
+    privilege = new TPrivilege("", TPrivilegeLevel.ALTER,
+        TPrivilegeScope.TABLE, false);
+    privilege.setServer_name("server1");
+    privilege.setDb_name("functional");
+    privilege.setTable_name("alltypes_view");
+    sentryService.grantRolePrivilege(USER, roleName, privilege);
+
     // all newdb w/ all on URI
     roleName = "all_newdb";
     sentryService.createRole(USER, roleName, true);
@@ -1352,6 +1389,8 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes REPLACE COLUMNS (c1 int)");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes CHANGE int_col c1 int");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes DROP int_col");
+    // Note: ALTER ... RENAME requires ALTER privileges at the TABLE level and
+    // CREATE privileges at the DATABASE level.
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes RENAME TO functional_seq_snap.t1");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET FILEFORMAT PARQUET");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
@@ -1362,11 +1401,28 @@ public class AuthorizationTest extends FrontendTestBase {
         "'hdfs://localhost:20500/test-warehouse/new_table'");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes PARTITION(year=2009, month=1) " +
         "SET LOCATION 'hdfs://localhost:20500/test-warehouse/new_table'");
-
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET CACHED IN 'testPool'");
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes RECOVER PARTITIONS");
 
+    // User has ALTER privilege only to modify tables.
+    AuthzOk("ALTER TABLE functional.alltypeserror ADD COLUMNS (c1 int)");
+    AuthzOk("ALTER TABLE functional.alltypeserror REPLACE COLUMNS (c1 int)");
+    AuthzOk("ALTER TABLE functional.alltypeserror CHANGE id c1 int");
+    AuthzOk("ALTER TABLE functional.alltypeserror DROP id");
+    AuthzOk("ALTER TABLE functional.alltypeserror RENAME TO functional_seq_snap.t1");
+    AuthzOk("ALTER TABLE functional.alltypeserror SET FILEFORMAT PARQUET");
+    AuthzOk("ALTER TABLE functional.alltypeserror SET LOCATION " +
+        "'/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional.alltypeserror SET TBLPROPERTIES ('a'='b', 'c'='d')");
+    AuthzOk("ALTER TABLE functional.alltypeserror SET LOCATION " +
+        "'hdfs://localhost:20500/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional.alltypeserror PARTITION(year=2009, month=1) " +
+        "SET LOCATION 'hdfs://localhost:20500/test-warehouse/new_table'");
+    AuthzOk("ALTER TABLE functional.alltypeserror SET CACHED IN 'testPool'");
+    AuthzOk("ALTER TABLE functional.alltypeserror RECOVER PARTITIONS");
+
     // Alter table and set location to a path the user does not have access to.
+    // User needs ALTER on table and ALL on URI.
     AuthzError("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
         "'hdfs://localhost:20500/test-warehouse/no_access'",
         "User '%s' does not have privileges to access: " +
@@ -1380,6 +1436,19 @@ public class AuthorizationTest extends FrontendTestBase {
         "User '%s' does not have privileges to access: " +
         "hdfs://localhost:20500/test-warehouse/no_access");
 
+    AuthzError("ALTER TABLE functional.alltypeserror SET LOCATION " +
+        "'hdfs://localhost:20500/test-warehouse/no_access'",
+        "User '%s' does not have privileges to access: " +
+        "hdfs://localhost:20500/test-warehouse/no_access");
+    AuthzError("ALTER TABLE functional.alltypeserror SET LOCATION " +
+        "'/test-warehouse/no_access'",
+        "User '%s' does not have privileges to access: " +
+        "hdfs://localhost:20500/test-warehouse/no_access");
+    AuthzError("ALTER TABLE functional.alltypeserror " +
+        "PARTITION(year=2009, month=1) SET LOCATION '/test-warehouse/no_access'",
+        "User '%s' does not have privileges to access: " +
+        "hdfs://localhost:20500/test-warehouse/no_access");
+
     // Add multiple partitions. User has access to location path.
     AuthzOk("ALTER TABLE functional_seq_snap.alltypes ADD " +
         "PARTITION(year=2011, month=1) " +
@@ -1398,6 +1467,24 @@ public class AuthorizationTest extends FrontendTestBase {
         "User '%s' does not have privileges to access: " +
         "hdfs://localhost:20510/test-warehouse/new_table");
 
+    // ALTER privilege only. Add multiple partitions. User has access to location path.
+    AuthzOk("ALTER TABLE functional.alltypeserror ADD " +
+        "PARTITION(year=2011, month=1) PARTITION(year=2011, month=2) " +
+        "LOCATION 'hdfs://localhost:20500/test-warehouse/new_table'");
+    // ALTER privilege only. For one new partition location is set to a path the user
+    // does not have access to.
+    AuthzError("ALTER TABLE functional.alltypeserror ADD " +
+        "PARTITION(year=2011, month=3) PARTITION(year=2011, month=4) " +
+        "LOCATION '/test-warehouse/no_access'",
+        "User '%s' does not have privileges to access: " +
+        "hdfs://localhost:20500/test-warehouse/no_access");
+    // ALTER privilege only.  Different filesystem, user has permission to base path.
+    AuthzError("ALTER TABLE functional.alltypeserror SET LOCATION " +
+        "'hdfs://localhost:20510/test-warehouse/new_table'",
+        "User '%s' does not have privileges to access: " +
+        "hdfs://localhost:20510/test-warehouse/new_table");
+
+    // User does not have ALTER privilege.
     AuthzError("ALTER TABLE functional.alltypes SET FILEFORMAT PARQUET",
         "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
     AuthzError("ALTER TABLE functional.alltypes ADD COLUMNS (c1 int)",
@@ -1438,6 +1525,11 @@ public class AuthorizationTest extends FrontendTestBase {
         "User '%s' does not have privileges to execute 'CREATE' on: " +
         "functional.alltypes");
 
+    // No privileges on target (new table).
+    AuthzError("ALTER TABLE functional_seq_snap.alltypes rename to functional.newtbl",
+        "User '%s' does not have privileges to execute 'CREATE' on: " +
+            "functional");
+
     // No privileges on target (existing view).
     AuthzError("ALTER TABLE functional_seq_snap.alltypes rename to " +
         "functional.alltypes_view",
@@ -1445,7 +1537,7 @@ public class AuthorizationTest extends FrontendTestBase {
         "functional.alltypes");
 
     // ALTER TABLE on a view does not reveal privileged information.
-    AuthzError("ALTER TABLE functional.alltypes_view rename to " +
+    AuthzError("ALTER TABLE functional.alltypes_view_sub rename to " +
         "functional_seq_snap.new_view",
         "User '%s' does not have privileges to execute 'ALTER' on: " +
         "functional.alltypes_view");
@@ -1488,6 +1580,14 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzOk("ALTER VIEW functional_seq_snap.alltypes_view rename to " +
         "functional_seq_snap.v1");
 
+    // ALTER privilege on view only. RENAME also requires CREATE privileges on the DB.
+    AuthzOk("ALTER VIEW functional.alltypes_view rename to functional_seq_snap.view_view_1");
+
+    // No create privileges on target db
+    AuthzError("ALTER VIEW functional.alltypes_view rename to functional.newview",
+        "User '%s' does not have privileges to execute 'CREATE' on: " +
+        "functional");
+
     // No privileges on target (existing table).
     AuthzError("ALTER VIEW functional_seq_snap.alltypes_view rename to " +
         "functional.alltypes",
@@ -1527,7 +1627,7 @@ public class AuthorizationTest extends FrontendTestBase {
         "User '%s' does not have privileges to execute 'ALTER' on: default.alltypes");
 
     // No permissions on target view.
-    AuthzError("alter view functional.alltypes_view as " +
+    AuthzError("alter view functional.alltypes_view_sub as " +
         "select * from functional.alltypesagg",
         "User '%s' does not have privileges to execute 'ALTER' on: " +
         "functional.alltypes_view");
@@ -1611,8 +1711,8 @@ public class AuthorizationTest extends FrontendTestBase {
     AuthzError("describe functional.complextypestbl.nested_struct",
         "User '%s' does not have privileges to access: functional.complextypestbl");
     // Insufficient privileges on view.
-    AuthzError("describe functional.alltypes_view",
-        "User '%s' does not have privileges to access: functional.alltypes_view");
+    AuthzError("describe functional.alltypes_view_sub",
+        "User '%s' does not have privileges to access: functional.alltypes_view_sub");
     // Insufficient privileges on db.
     AuthzError("describe functional_rc.alltypes",
         "User '%s' does not have privileges to access: functional_rc.alltypes");
@@ -1794,7 +1894,8 @@ public class AuthorizationTest extends FrontendTestBase {
     tables = fe_.getTableNames("functional",
         PatternMatcher.createHivePatternMatcher("alltypes*|view_view"), USER);
     List<String> expectedTables = Lists.newArrayList(
-        "alltypes", "alltypesagg", "alltypessmall", "alltypestiny", "view_view");
+        "alltypes", "alltypes_view", "alltypesagg", "alltypeserror", "alltypessmall",
+        "alltypestiny", "view_view");
     Assert.assertEquals(expectedTables, tables);
   }
 
@@ -2372,6 +2473,48 @@ public class AuthorizationTest extends FrontendTestBase {
     }
   }
 
+  @Test
+  public void TestServerLevelAlter() throws ImpalaException {
+    // TODO: Add test support for dynamically changing privileges for
+    // file-based policy.
+    if (ctx_.authzConfig.isFileBasedPolicy()) return;
+
+    SentryPolicyService sentryService =
+        new SentryPolicyService(ctx_.authzConfig.getSentryConfig());
+
+    // User has ALTER privilege on server.
+    String roleName = "alter_role";
+    try {
+      sentryService.createRole(USER, roleName, true);
+      TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.ALTER,
+          TPrivilegeScope.SERVER, false);
+      privilege.setServer_name("server1");
+      sentryService.grantRolePrivilege(USER, roleName, privilege);
+      sentryService.grantRoleToGroup(USER, roleName, USER.getName());
+      ctx_.catalog.reset();
+
+      AuthzOk("ALTER TABLE functional_rc.alltypes ADD COLUMNS (c1 int)");
+      AuthzOk("ALTER TABLE functional_rc.alltypes REPLACE COLUMNS (c1 int)");
+      AuthzOk("ALTER TABLE functional_rc.alltypes CHANGE int_col c1 int");
+      AuthzOk("ALTER TABLE functional_rc.alltypes DROP int_col");
+      AuthzOk("ALTER TABLE functional_rc.alltypes RENAME TO functional_seq_snap.t1");
+      AuthzOk("ALTER TABLE functional_rc.alltypes SET FILEFORMAT PARQUET");
+      AuthzOk("ALTER TABLE functional_rc.alltypes SET LOCATION " +
+          "'/test-warehouse/new_table'");
+      AuthzOk("ALTER TABLE functional_rc.alltypes SET TBLPROPERTIES " +
+          "('a'='b', 'c'='d')");
+      AuthzOk("ALTER TABLE functional_rc.alltypes SET LOCATION " +
+          "'hdfs://localhost:20500/test-warehouse/new_table'");
+      AuthzOk("ALTER TABLE functional_rc.alltypes PARTITION(year=2009, month=1) " +
+          "SET LOCATION 'hdfs://localhost:20500/test-warehouse/new_table'");
+      AuthzOk("ALTER TABLE functional_rc.alltypes SET CACHED IN 'testPool'");
+      AuthzOk("ALTER TABLE functional_rc.alltypes RECOVER PARTITIONS");
+    } finally {
+      sentryService.dropRole(USER, roleName, true);
+      ctx_.catalog.reset();
+    }
+  }
+
   private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user)
       throws ImpalaException {
     Frontend fe = new Frontend(authzConfig, ctx_.catalog);

http://git-wip-us.apache.org/repos/asf/impala/blob/22b10efe/fe/src/test/resources/authz-policy.ini.template
----------------------------------------------------------------------
diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template
index aeb3911..82b1060 100644
--- a/fe/src/test/resources/authz-policy.ini.template
+++ b/fe/src/test/resources/authz-policy.ini.template
@@ -27,7 +27,9 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\
           select_column_level_functional_avro, upper_case_uri,\
           refresh_functional_text_lzo, refresh_functional_alltypesagg,\
           refresh_functional_view_view, insert_functional_text_lzo,\
-          create_functional_text_lzo, libtestudfs_uri
+          create_functional_text_lzo, alter_functional_text_lzo,\
+          alter_functional_alltypeserror, alter_functional_alltypes_view,\
+          libtestudfs_uri
 auth_to_local_group = test_role
 server_admin = all_server
 
@@ -53,10 +55,15 @@ insert_parquet = server=server1->db=functional_parquet->table=*->action=insert
 refresh_functional_text_lzo = server=server1->db=functional_text_lzo->action=refresh
 refresh_functional_alltypesagg =\
     server=server1->db=functional->table=alltypesagg->action=refresh
+alter_functional_alltypeserror =\
+    server=server1->db=functional->table=alltypeserror->action=alter
 refresh_functional_view_view =\
     server=server1->db=functional->table=view_view->action=refresh
+alter_functional_alltypes_view =\
+    server=server1->db=functional->table=alltypes_view->action=alter
 insert_functional_text_lzo = server=server1->db=functional_text_lzo->action=insert
 create_functional_text_lzo = server=server1->db=functional_text_lzo->action=create
+alter_functionl_text_lzo = server=server1->db=functional_text_lzo->action=alter
 select_column_level_functional =\
     server=server1->db=functional->table=alltypessmall->column=id->action=select,\
     server=server1->db=functional->table=alltypessmall->column=int_col->action=select,\