diff --git a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerCheckInvocation.java b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerCheckInvocation.java new file mode 100644 index 0000000..c91b15c --- /dev/null +++ b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerCheckInvocation.java @@ -0,0 +1,177 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hive.ql.security.authorization.plugin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.ql.CommandNeedRetryException; +import org.apache.hadoop.hive.ql.Driver; +import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse; +import org.apache.hadoop.hive.ql.security.HiveAuthenticationProvider; +import org.apache.hadoop.hive.ql.security.SessionStateUserAuthenticator; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType; +import org.apache.hadoop.hive.ql.session.SessionState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; +import org.mockito.Mockito; + +/** + * Test HiveAuthorizer api invocation + */ +public class TestHiveAuthorizerCheckInvocation { + protected static HiveConf conf; + protected static Driver driver; + private static final String tableName = TestHiveAuthorizerCheckInvocation.class.getSimpleName(); + static HiveAuthorizer mockedAuthorizer; + + /** + * This factory creates a mocked HiveAuthorizer class. Use the mocked class to + * capture the argument passed to it in the test case. + */ + static class MockedHiveAuthorizerFactory implements HiveAuthorizerFactory { + @Override + public HiveAuthorizer createHiveAuthorizer(HiveMetastoreClientFactory metastoreClientFactory, + HiveConf conf, HiveAuthenticationProvider authenticator) { + TestHiveAuthorizerCheckInvocation.mockedAuthorizer = Mockito.mock(HiveAuthorizer.class); + return TestHiveAuthorizerCheckInvocation.mockedAuthorizer; + } + + } + + @BeforeClass + public static void beforeTest() throws Exception { + conf = new HiveConf(); + + // Turn on mocked authorization + conf.setVar(ConfVars.HIVE_AUTHORIZATION_MANAGER, MockedHiveAuthorizerFactory.class.getName()); + conf.setVar(ConfVars.HIVE_AUTHENTICATOR_MANAGER, SessionStateUserAuthenticator.class.getName()); + conf.setBoolVar(ConfVars.HIVE_AUTHORIZATION_ENABLED, true); + conf.setBoolVar(ConfVars.HIVE_SUPPORT_CONCURRENCY, false); + conf.setBoolVar(ConfVars.HIVE_SERVER2_ENABLE_DOAS, false); + + SessionState.start(conf); + driver = new Driver(conf); + CommandProcessorResponse resp = driver.run("create table " + tableName + + " (i int, j int, k string) partitioned by (city string, date string) "); + assertEquals(0, resp.getResponseCode()); + } + + @AfterClass + public static void afterTests() throws Exception { + driver.close(); + } + + @Test + public void testInputSomeColumnsUsed() throws HiveAuthzPluginException, HiveAccessControlException, + CommandNeedRetryException { + + reset(mockedAuthorizer); + int status = driver.compile("select i from " + tableName + + " where k = 'X' and city = 'Scottsdale-AZ' "); + assertEquals(0, status); + + List inputs = getHivePrivilegeObjectInputs(); + checkSingleTableInput(inputs); + HivePrivilegeObject tableObj = inputs.get(0); + assertEquals("no of columns used", 3, tableObj.getColumns().size()); + assertEquals("Columns used", Arrays.asList("city", "i", "k"), + getSortedList(tableObj.getColumns())); + } + + private List getSortedList(Set columns) { + List sortedCols = new ArrayList(columns); + Collections.sort(sortedCols); + return sortedCols; + } + + @Test + public void testInputAllColumnsUsed() throws HiveAuthzPluginException, HiveAccessControlException, + CommandNeedRetryException { + + reset(mockedAuthorizer); + int status = driver.compile("select * from " + tableName + " order by i"); + assertEquals(0, status); + + List inputs = getHivePrivilegeObjectInputs(); + checkSingleTableInput(inputs); + HivePrivilegeObject tableObj = inputs.get(0); + assertEquals("no of columns used", 5, tableObj.getColumns().size()); + assertEquals("Columns used", Arrays.asList("city", "date", "i", "j", "k"), + getSortedList(tableObj.getColumns())); + } + + @Test + public void testInputNoColumnsUsed() throws HiveAuthzPluginException, HiveAccessControlException, + CommandNeedRetryException { + + reset(mockedAuthorizer); + int status = driver.compile("describe " + tableName); + assertEquals(0, status); + + List inputs = getHivePrivilegeObjectInputs(); + checkSingleTableInput(inputs); + HivePrivilegeObject tableObj = inputs.get(0); + assertNull("columns used", tableObj.getColumns()); + } + + private void checkSingleTableInput(List inputs) { + assertEquals("number of inputs", 1, inputs.size()); + + HivePrivilegeObject tableObj = inputs.get(0); + assertEquals("input type", HivePrivilegeObjectType.TABLE_OR_VIEW, tableObj.getType()); + assertTrue("table name", tableName.equalsIgnoreCase(tableObj.getObjectName())); + } + + /** + * @return the inputs passed in current call to authorizer.checkPrivileges + * @throws HiveAuthzPluginException + * @throws HiveAccessControlException + */ + private List getHivePrivilegeObjectInputs() throws HiveAuthzPluginException, + HiveAccessControlException { + // Create argument capturer + // a class variable cast to this generic of generic class + Class> class_listPrivObjects = (Class) List.class; + ArgumentCaptor> inputsCapturer = ArgumentCaptor + .forClass(class_listPrivObjects); + + verify(mockedAuthorizer).checkPrivileges(any(HiveOperationType.class), + inputsCapturer.capture(), Matchers.anyListOf(HivePrivilegeObject.class), + any(HiveAuthzContext.class)); + + return inputsCapturer.getValue(); + } + +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/Driver.java b/ql/src/java/org/apache/hadoop/hive/ql/Driver.java index e512199..cba5cfa 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/Driver.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/Driver.java @@ -82,6 +82,7 @@ import org.apache.hadoop.hive.ql.optimizer.ppr.PartitionPruner; import org.apache.hadoop.hive.ql.parse.ASTNode; import org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer; +import org.apache.hadoop.hive.ql.parse.ColumnAccessInfo; import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHook; import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContext; import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContextImpl; @@ -503,8 +504,13 @@ public static void doAuthorization(BaseSemanticAnalyzer sem, String command) Hive db = sem.getDb(); if (ss.isAuthorizationModeV2()) { - doAuthorizationV2(ss, op, inputs, outputs, command); - return; + // get mapping of tables to columns used + ColumnAccessInfo colAccessInfo = sem.getColumnAccessInfo(); + // colAccessInfo is set only in case of SemanticAnalyzer + Map> tab2Cols = colAccessInfo != null ? colAccessInfo + .getTableToColumnAccessMap() : null; + doAuthorizationV2(ss, op, inputs, outputs, command, tab2Cols); + return; } if (op == null) { throw new HiveException("Operation should not be null"); @@ -583,56 +589,9 @@ public static void doAuthorization(BaseSemanticAnalyzer sem, String command) } } - //for a select or create-as-select query, populate the partition to column (par2Cols) or - // table to columns mapping (tab2Cols) - if (op.equals(HiveOperation.CREATETABLE_AS_SELECT) - || op.equals(HiveOperation.QUERY)) { - SemanticAnalyzer querySem = (SemanticAnalyzer) sem; - ParseContext parseCtx = querySem.getParseContext(); - Map tsoTopMap = parseCtx.getTopToTable(); - - for (Map.Entry> topOpMap : querySem - .getParseContext().getTopOps().entrySet()) { - Operator topOp = topOpMap.getValue(); - if (topOp instanceof TableScanOperator - && tsoTopMap.containsKey(topOp)) { - TableScanOperator tableScanOp = (TableScanOperator) topOp; - Table tbl = tsoTopMap.get(tableScanOp); - List neededColumnIds = tableScanOp.getNeededColumnIDs(); - List columns = tbl.getCols(); - List cols = new ArrayList(); - for (int i = 0; i < neededColumnIds.size(); i++) { - cols.add(columns.get(neededColumnIds.get(i)).getName()); - } - //map may not contain all sources, since input list may have been optimized out - //or non-existent tho such sources may still be referenced by the TableScanOperator - //if it's null then the partition probably doesn't exist so let's use table permission - if (tbl.isPartitioned() && - tableUsePartLevelAuth.get(tbl.getTableName()) == Boolean.TRUE) { - String alias_id = topOpMap.getKey(); - - PrunedPartitionList partsList = PartitionPruner.prune(tableScanOp, - parseCtx, alias_id); - Set parts = partsList.getPartitions(); - for (Partition part : parts) { - List existingCols = part2Cols.get(part); - if (existingCols == null) { - existingCols = new ArrayList(); - } - existingCols.addAll(cols); - part2Cols.put(part, existingCols); - } - } else { - List existingCols = tab2Cols.get(tbl); - if (existingCols == null) { - existingCols = new ArrayList(); - } - existingCols.addAll(cols); - tab2Cols.put(tbl, existingCols); - } - } - } - } + getTablePartitionUsedColumns(op, sem, tab2Cols, part2Cols, tableUsePartLevelAuth); + + // cache the results for table authorization Set tableAuthChecked = new HashSet(); @@ -683,8 +642,65 @@ public static void doAuthorization(BaseSemanticAnalyzer sem, String command) } } + private static void getTablePartitionUsedColumns(HiveOperation op, BaseSemanticAnalyzer sem, + Map> tab2Cols, Map> part2Cols, + Map tableUsePartLevelAuth) throws HiveException { + // for a select or create-as-select query, populate the partition to column + // (par2Cols) or + // table to columns mapping (tab2Cols) + if (op.equals(HiveOperation.CREATETABLE_AS_SELECT) + || op.equals(HiveOperation.QUERY)) { + SemanticAnalyzer querySem = (SemanticAnalyzer) sem; + ParseContext parseCtx = querySem.getParseContext(); + Map tsoTopMap = parseCtx.getTopToTable(); + + for (Map.Entry> topOpMap : querySem + .getParseContext().getTopOps().entrySet()) { + Operator topOp = topOpMap.getValue(); + if (topOp instanceof TableScanOperator + && tsoTopMap.containsKey(topOp)) { + TableScanOperator tableScanOp = (TableScanOperator) topOp; + Table tbl = tsoTopMap.get(tableScanOp); + List neededColumnIds = tableScanOp.getNeededColumnIDs(); + List columns = tbl.getCols(); + List cols = new ArrayList(); + for (int i = 0; i < neededColumnIds.size(); i++) { + cols.add(columns.get(neededColumnIds.get(i)).getName()); + } + //map may not contain all sources, since input list may have been optimized out + //or non-existent tho such sources may still be referenced by the TableScanOperator + //if it's null then the partition probably doesn't exist so let's use table permission + if (tbl.isPartitioned() && + tableUsePartLevelAuth.get(tbl.getTableName()) == Boolean.TRUE) { + String alias_id = topOpMap.getKey(); + + PrunedPartitionList partsList = PartitionPruner.prune(tableScanOp, + parseCtx, alias_id); + Set parts = partsList.getPartitions(); + for (Partition part : parts) { + List existingCols = part2Cols.get(part); + if (existingCols == null) { + existingCols = new ArrayList(); + } + existingCols.addAll(cols); + part2Cols.put(part, existingCols); + } + } else { + List existingCols = tab2Cols.get(tbl); + if (existingCols == null) { + existingCols = new ArrayList(); + } + existingCols.addAll(cols); + tab2Cols.put(tbl, existingCols); + } + } + } + } + + } + private static void doAuthorizationV2(SessionState ss, HiveOperation op, HashSet inputs, - HashSet outputs, String command) throws HiveException { + HashSet outputs, String command, Map> tab2cols) throws HiveException { HiveAuthzContext.Builder authzContextBuilder = new HiveAuthzContext.Builder(); @@ -696,11 +712,34 @@ private static void doAuthorizationV2(SessionState ss, HiveOperation op, HashSet HiveOperationType hiveOpType = getHiveOperationType(op); List inputsHObjs = getHivePrivObjects(inputs); + updateInputColumnInfo(inputsHObjs, tab2cols); + List outputHObjs = getHivePrivObjects(outputs); ss.getAuthorizerV2().checkPrivileges(hiveOpType, inputsHObjs, outputHObjs, authzContextBuilder.build()); return; } + /** + * Add column information for input table objects + * @param inputsHObjs input HivePrivilegeObject + * @param map table to used input columns mapping + */ + private static void updateInputColumnInfo(List inputsHObjs, + Map> tableName2Cols) { + if(tableName2Cols == null) { + return; + } + for(HivePrivilegeObject inputObj : inputsHObjs){ + if(inputObj.getType() != HivePrivilegeObjectType.TABLE_OR_VIEW){ + // input columns are relevant only for tables or views + continue; + } + Set cols = tableName2Cols.get(Table.getCompleteName(inputObj.getDbname(), + inputObj.getObjectName())); + inputObj.setColumns(cols); + } + } + private static List getHivePrivObjects(HashSet privObjects) { List hivePrivobjs = new ArrayList(); if(privObjects == null){ diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java index 7d62f45..61fbaf8 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -598,10 +599,13 @@ private int showGrants(ShowGrantDesc showGrantDesc) throws HiveException { HiveAuthorizer authorizer = getSessionAuthorizer(); try { + Set colSet = showGrantDesc.getColumns() != null ? new HashSet( + showGrantDesc.getColumns()) : null; List privInfos = authorizer.showPrivileges( AuthorizationUtils.getHivePrincipal(showGrantDesc.getPrincipalDesc()), AuthorizationUtils.getHivePrivilegeObject(showGrantDesc.getHiveObj(), - showGrantDesc.getColumns())); + colSet + )); boolean testMode = conf.getBoolVar(HiveConf.ConfVars.HIVE_IN_TEST); writeToFile(writeGrantInfo(privInfos, testMode), showGrantDesc.getResFile()); } catch (IOException e) { diff --git a/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java b/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java index 2cedcee..2f13ac2 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java @@ -933,7 +933,11 @@ public boolean canWrite() { * @return include the db name */ public String getCompleteName() { - return getDbName() + "@" + getTableName(); + return getCompleteName(getDbName(), getTableName()); + } + + public static String getCompleteName(String dbName, String tabName) { + return dbName + "@" + tabName; } /** diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java index d38270c..55ad1d3 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -19,7 +19,6 @@ package org.apache.hadoop.hive.ql.parse; import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVESTATSDBCLASS; -import static org.apache.hadoop.hive.metastore.MetaStoreUtils.DATABASE_WAREHOUSE_SUFFIX; import java.io.IOException; import java.io.Serializable; @@ -31,10 +30,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; +import java.util.UUID; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -2328,13 +2327,13 @@ private Operator genFilterPlan(QB qb, ASTNode condn, Operator input) * for inner joins push a 'is not null predicate' to the join sources for * every non nullSafe predicate. */ - private Operator genNotNullFilterForJoinSourcePlan(QB qb, Operator input, + private Operator genNotNullFilterForJoinSourcePlan(QB qb, Operator input, QBJoinTree joinTree, ExprNodeDesc[] joinKeys) throws SemanticException { if (qb == null || joinTree == null) { return input; } - + if (!joinTree.getNoOuterJoin()) { return input; } @@ -9501,7 +9500,11 @@ public void analyzeInternal(ASTNode ast) throws SemanticException { // Generate column access stats if required - wait until column pruning takes place // during optimization - if (HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS) == true) { + boolean isColumnInfoNeedForAuth = SessionState.get().isAuthorizationModeV2() + && HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED); + + if (isColumnInfoNeedForAuth + || HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS) == true) { ColumnAccessAnalyzer columnAccessAnalyzer = new ColumnAccessAnalyzer(pCtx); setColumnAccessInfo(columnAccessAnalyzer.analyzeColumnAccess()); } @@ -9548,7 +9551,7 @@ private void enforceScanLimits(ParseContext pCtx, FetchTask fTask) if (((TableScanDesc)topOp.getConf()).getIsMetadataOnly()) { continue; } - PrunedPartitionList parts = pCtx.getOpToPartList().get((TableScanOperator) topOp); + PrunedPartitionList parts = pCtx.getOpToPartList().get(topOp); if (parts.getPartitions().size() > scanLimit) { throw new SemanticException(ErrorMsg.PARTITION_SCAN_LIMIT_EXCEEDED, "" + parts.getPartitions().size(), "" + parts.getSourceTable().getTableName(), "" @@ -10169,7 +10172,7 @@ private ASTNode analyzeCreateTable(ASTNode ast, QB qb) String dbName = qualified.length == 1 ? SessionState.get().getCurrentDatabase() : qualified[0]; Database database = getDatabase(dbName); outputs.add(new WriteEntity(database, WriteEntity.WriteType.DDL_SHARED)); - + if (isTemporary) { if (partCols.size() > 0) { throw new SemanticException("Partition columns are not supported on temporary tables"); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/AuthorizationUtils.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/AuthorizationUtils.java index 698cac5..5c94217 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/AuthorizationUtils.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/AuthorizationUtils.java @@ -17,6 +17,10 @@ */ package org.apache.hadoop.hive.ql.security.authorization; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + import org.apache.hadoop.classification.InterfaceAudience.LimitedPrivate; import org.apache.hadoop.hive.metastore.api.HiveObjectPrivilege; import org.apache.hadoop.hive.metastore.api.HiveObjectRef; @@ -24,8 +28,8 @@ import org.apache.hadoop.hive.metastore.api.PrincipalType; import org.apache.hadoop.hive.metastore.api.PrivilegeGrantInfo; import org.apache.hadoop.hive.ql.ErrorMsg; -import org.apache.hadoop.hive.ql.hooks.Entity; import org.apache.hadoop.hive.ql.exec.Utilities; +import org.apache.hadoop.hive.ql.hooks.Entity; import org.apache.hadoop.hive.ql.hooks.Entity.Type; import org.apache.hadoop.hive.ql.hooks.WriteEntity; import org.apache.hadoop.hive.ql.hooks.WriteEntity.WriteType; @@ -42,9 +46,6 @@ import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType; import org.apache.hadoop.hive.ql.session.SessionState; -import java.util.ArrayList; -import java.util.List; - /** * Utility code shared by hive internal code and sql standard authorization plugin implementation */ @@ -173,7 +174,7 @@ public static HivePrivilegeObject getHiveObjectRef(HiveObjectRef privObj) throws } public static HivePrivilegeObject getHivePrivilegeObject( - PrivilegeObjectDesc privSubjectDesc, List columns) throws HiveException { + PrivilegeObjectDesc privSubjectDesc, Set columns) throws HiveException { // null means ALL for show grants, GLOBAL for grant/revoke HivePrivilegeObjectType objectType = null; diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HivePrivilegeObject.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HivePrivilegeObject.java index 1020622..9e9ef71 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HivePrivilegeObject.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HivePrivilegeObject.java @@ -17,9 +17,12 @@ */ package org.apache.hadoop.hive.ql.security.authorization.plugin; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Set; import org.apache.hadoop.hive.common.classification.InterfaceAudience.LimitedPrivate; import org.apache.hadoop.hive.common.classification.InterfaceStability.Unstable; @@ -57,9 +60,18 @@ public int compareTo(HivePrivilegeObject o) { return compare; } - private int compare(List o1, List o2) { - for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) { - int compare = o1.get(i).compareTo(o2.get(i)); + private int compare(Collection o1, Collection o2) { + Iterator it1 = o1.iterator(); + Iterator it2 = o2.iterator(); + while (it1.hasNext()) { + if (!it2.hasNext()) { + break; + } + String s1 = it1.next(); + String s2 = it2.next(); + int compare = s1 != null ? + (s2 != null ? s1.compareTo(s2) : 1) : + (s2 != null ? -1 : 0); if (compare != 0) { return compare; } @@ -79,7 +91,7 @@ private int compare(List o1, List o2) { private final String objectName; private final List commandParams; private final List partKeys; - private final List columns; + private Set columns; private final HivePrivObjectActionType actionType; public HivePrivilegeObject(HivePrivilegeObjectType type, String dbname, String objectName) { @@ -94,9 +106,8 @@ public HivePrivilegeObject(HivePrivilegeObjectType type, String dbname, String o public HivePrivilegeObject(HivePrivilegeObjectType type, String dbname, String objectName, List partKeys, String column) { this(type, dbname, objectName, partKeys, - column == null ? null : new ArrayList(Arrays.asList(column)), + column == null ? null : new HashSet(Arrays.asList(column)), HivePrivObjectActionType.OTHER, null); - } /** @@ -110,12 +121,12 @@ public static HivePrivilegeObject createHivePrivilegeObject(List cmdPara } public HivePrivilegeObject(HivePrivilegeObjectType type, String dbname, String objectName, - List partKeys, List columns, List commandParams) { + List partKeys, Set columns, List commandParams) { this(type, dbname, objectName, partKeys, columns, HivePrivObjectActionType.OTHER, commandParams); } public HivePrivilegeObject(HivePrivilegeObjectType type, String dbname, String objectName, - List partKeys, List columns, HivePrivObjectActionType actionType, + List partKeys, Set columns, HivePrivObjectActionType actionType, List commandParams) { this.type = type; this.dbname = dbname; @@ -153,7 +164,13 @@ public HivePrivObjectActionType getActionType() { return partKeys; } - public List getColumns() { + /** + * Applicable columns in this object + * In case of DML read operations, this is the set of columns being used. + * Column information is not set for DDL operations and for tables being written into + * @return list of applicable columns + */ + public Set getColumns() { return columns; } @@ -202,4 +219,8 @@ private String getDbObjectName(String dbname2, String objectName2) { return (dbname == null ? "" : dbname + ".") + objectName; } + public void setColumns(Set columnms) { + this.columns = columnms; + } + } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HiveV1Authorizer.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HiveV1Authorizer.java index c747c33..fbc0090 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HiveV1Authorizer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/HiveV1Authorizer.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.metastore.Warehouse; @@ -318,7 +319,7 @@ private void grantOrRevokeRole(List principals, List role privs.addAll(hive.showPrivilegeGrant(HiveObjectType.DATABASE, name, type, dbObj.getName(), null, null, null)); } else { - List columns = privObj.getColumns(); + Set columns = privObj.getColumns(); if (columns != null && !columns.isEmpty()) { // show column level privileges for (String columnName : columns) {