This is an automated email from the ASF dual-hosted git repository.

vihangk1 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new 7c19fc8  HIVE-24026: HMS/Ranger Spark view authorization plan (Sai 
Hemanth Gantasala reviewed by Vihang Karajgaonkar)
7c19fc8 is described below

commit 7c19fc8fb12a1ff4afe9fe7cdadc0988fc0bc1f7
Author: saihemanth-cloudera 
<68923650+saihemanth-cloud...@users.noreply.github.com>
AuthorDate: Wed Sep 2 14:05:01 2020 -0700

    HIVE-24026: HMS/Ranger Spark view authorization plan (Sai Hemanth Gantasala 
reviewed by Vihang Karajgaonkar)
    
    Spark client can create/alter/drop a view (#1391)
---
 .../authorization/command/CommandAuthorizerV2.java | 51 +++++++++++++++++++++-
 .../plugin/metastore/HiveMetaStoreAuthorizer.java  | 13 ++++--
 .../metastore/TestHiveMetaStoreAuthorizer.java     | 35 +++++++++++++--
 3 files changed, 91 insertions(+), 8 deletions(-)

diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/command/CommandAuthorizerV2.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/command/CommandAuthorizerV2.java
index e9a278d..08fcdc5 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/command/CommandAuthorizerV2.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/command/CommandAuthorizerV2.java
@@ -24,6 +24,10 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Map.Entry;
 
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.metastore.HiveMetaStore;
+import org.apache.hadoop.hive.metastore.TableType;
 import org.apache.hadoop.hive.metastore.api.Database;
 import org.apache.hadoop.hive.ql.exec.FunctionInfo;
 import org.apache.hadoop.hive.ql.exec.FunctionUtils;
@@ -104,8 +108,25 @@ final class CommandAuthorizerV2 {
         continue;
       }
       if (privObject instanceof ReadEntity && 
!((ReadEntity)privObject).isDirect()) {
-        // This ReadEntity represents one of the underlying tables/views of a 
view, so skip it.
-        continue;
+        // This ReadEntity represents one of the underlying tables/views of a 
view, skip it if
+        // it's not inside a deferred authorized view.
+        ReadEntity reTable = (ReadEntity)privObject;
+        Boolean isDeferred = false;
+        if( reTable.getParents() != null && reTable.getParents().size() > 0){
+          for( ReadEntity re: reTable.getParents()){
+            if (re.getTyp() == Type.TABLE && re.getTable() != null ) {
+              Table t = re.getTable();
+              if(!isDeferredAuthView(t)){
+                continue;
+              }else{
+                isDeferred = true;
+              }
+            }
+          }
+        }
+        if(!isDeferred){
+          continue;
+        }
       }
       if (privObject instanceof WriteEntity && 
((WriteEntity)privObject).isTempURI()) {
         // do not authorize temporary uris
@@ -121,6 +142,32 @@ final class CommandAuthorizerV2 {
     return hivePrivobjs;
   }
 
+  /**
+   * A deferred authorization view is view created by non-super user like 
spark-user. This view contains a parameter "Authorized"
+   * set to false, so ranger will not authorize it during view creation. When 
a select statement is issued, then the ranger authorizes
+   * the under lying tables.
+   * @param Table t
+   * @return boolean value
+   */
+  private static boolean isDeferredAuthView(Table t){
+    String tableType = t.getTTable().getTableType();
+    String authorizedKeyword = "Authorized";
+    boolean isView = false;
+    if (TableType.MATERIALIZED_VIEW.name().equals(tableType) || 
TableType.VIRTUAL_VIEW.name().equals(tableType)) {
+      isView = true;
+    }
+    if(isView){
+      Map<String, String> params = t.getParameters();
+      if (params != null && params.containsKey(authorizedKeyword)) {
+        String authorizedValue = params.get(authorizedKeyword);
+        if ("false".equalsIgnoreCase(authorizedValue)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   private static void addHivePrivObject(Entity privObject, Map<String, 
List<String>> tableName2Cols,
       List<HivePrivilegeObject> hivePrivObjs) {
     HivePrivilegeObjectType privObjType = 
AuthorizationUtils.getHivePrivilegeObjectType(privObject.getType());
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/HiveMetaStoreAuthorizer.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/HiveMetaStoreAuthorizer.java
index fb9d6dd..23db0da 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/HiveMetaStoreAuthorizer.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/HiveMetaStoreAuthorizer.java
@@ -60,6 +60,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * HiveMetaStoreAuthorizer :  Do authorization checks on MetaStore Events in 
MetaStorePreEventListener
@@ -381,19 +382,25 @@ public class HiveMetaStoreAuthorizer extends 
MetaStorePreEventListener implement
         case CREATE_TABLE:
           authzEvent = new CreateTableEvent(preEventContext);
           if (isViewOperation(preEventContext) && 
(!isSuperUser(getCurrentUser(authzEvent)))) {
-            throw new MetaException(getErrorMessage("CREATE_VIEW", 
getCurrentUser(authzEvent)));
+            //we allow view to be created, but mark it as having not been 
authorized
+            PreCreateTableEvent pcte = (PreCreateTableEvent)preEventContext;
+            Map<String, String> params = pcte.getTable().getParameters();
+            params.put("Authorized", "false");
           }
           break;
         case ALTER_TABLE:
           authzEvent = new AlterTableEvent(preEventContext);
           if (isViewOperation(preEventContext) && 
(!isSuperUser(getCurrentUser(authzEvent)))) {
-            throw new MetaException(getErrorMessage("ALTER_VIEW", 
getCurrentUser(authzEvent)));
+            //we allow view to be altered, but mark it as having not been 
authorized
+            PreAlterTableEvent pcte = (PreAlterTableEvent)preEventContext;
+            Map<String, String> params = pcte.getNewTable().getParameters();
+            params.put("Authorized", "false");
           }
           break;
         case DROP_TABLE:
           authzEvent = new DropTableEvent(preEventContext);
           if (isViewOperation(preEventContext) && 
(!isSuperUser(getCurrentUser(authzEvent)))) {
-            throw new MetaException(getErrorMessage("DROP_VIEW", 
getCurrentUser(authzEvent)));
+            //TODO: do we need to check Authorized flag?
           }
           break;
         case ADD_PARTITION:
diff --git 
a/ql/src/test/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/TestHiveMetaStoreAuthorizer.java
 
b/ql/src/test/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/TestHiveMetaStoreAuthorizer.java
index f99765f..f2952ad 100644
--- 
a/ql/src/test/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/TestHiveMetaStoreAuthorizer.java
+++ 
b/ql/src/test/org/apache/hadoop/hive/ql/security/authorization/plugin/metastore/TestHiveMetaStoreAuthorizer.java
@@ -36,10 +36,12 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 import org.junit.Before;
 import org.junit.Test;
+import java.util.Map;
 
 import java.io.File;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 /*
 Test whether HiveAuthorizer for MetaStore operation is trigger and 
HiveMetaStoreAuthzInfo is created by HiveMetaStoreAuthorizer
@@ -138,10 +140,37 @@ public class TestHiveMetaStoreAuthorizer {
               .setOwner(authorizedUser)
               .build(conf);
       hmsHandler.create_table(viewObj);
+      Map<String, String> params = viewObj.getParameters();
+      assertTrue(params.containsKey("Authorized"));
+      assertTrue("false".equalsIgnoreCase(params.get("Authorized")));
     } catch (Exception e) {
-      String err = e.getMessage();
-      String expected = "Operation type CREATE_VIEW not allowed for user:" + 
authorizedUser;
-      assertEquals(expected, err);
+      // no Exceptions for user same as normal user is now allowed CREATE_VIEW 
operation
+    }
+  }
+
+  @Test
+  public void testC2_AlterView_anyUser() throws Exception{
+    
UserGroupInformation.setLoginUser(UserGroupInformation.createRemoteUser(authorizedUser));
+    try {
+      Table viewObj = new TableBuilder()
+              .setTableName(viewName)
+              .setType(TableType.VIRTUAL_VIEW.name())
+              .addCol("name", ColumnType.STRING_TYPE_NAME)
+              .setOwner(authorizedUser)
+              .build(conf);
+      hmsHandler.create_table(viewObj);
+      viewObj = new TableBuilder()
+              .setTableName(viewName)
+              .setType(TableType.VIRTUAL_VIEW.name())
+              .addCol("dep", ColumnType.STRING_TYPE_NAME)
+              .setOwner(authorizedUser)
+              .build(conf);
+      hmsHandler.alter_table("default", viewName, viewObj);
+      Map<String, String> params = viewObj.getParameters();
+      assertTrue(params.containsKey("Authorized"));
+      assertTrue("false".equalsIgnoreCase(params.get("Authorized")));
+    } catch (Exception e) {
+      // no Exceptions for user same as normal user is now allowed Alter_VIEW 
operation
     }
   }
 

Reply via email to