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 } }