This is an automated email from the ASF dual-hosted git repository. kgyrtkirk 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 78b20c8 HIVE-25680 : Authorize #get_table_meta HiveMetastore Server API to use any of the HiveMetastore Authorization model (#2770) (Syed Shameerur Rahman reviewed by Zoltan Haindrich) 78b20c8 is described below commit 78b20c803ef2e75a7fe830325df2c19c15b203a3 Author: Syed Shameerur Rahman <rhma...@amazon.com> AuthorDate: Tue Nov 23 13:31:36 2021 +0530 HIVE-25680 : Authorize #get_table_meta HiveMetastore Server API to use any of the HiveMetastore Authorization model (#2770) (Syed Shameerur Rahman reviewed by Zoltan Haindrich) --- ...stMetastoreClientSideAuthorizationProvider.java | 145 +++++++++++++++++++++ .../apache/hadoop/hive/metastore/HMSHandler.java | 52 ++++++++ 2 files changed, 197 insertions(+) diff --git a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/TestMetastoreClientSideAuthorizationProvider.java b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/TestMetastoreClientSideAuthorizationProvider.java new file mode 100644 index 0000000..dbd71cb --- /dev/null +++ b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/TestMetastoreClientSideAuthorizationProvider.java @@ -0,0 +1,145 @@ +/* + * 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; + +import com.google.common.collect.Lists; +import org.apache.hadoop.hive.cli.CliSessionState; +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.metastore.HiveMetaStoreClient; +import org.apache.hadoop.hive.metastore.MetaStoreTestUtils; +import org.apache.hadoop.hive.metastore.api.TableMeta; +import org.apache.hadoop.hive.ql.DriverFactory; +import org.apache.hadoop.hive.ql.IDriver; +import org.apache.hadoop.hive.ql.security.authorization.DefaultHiveAuthorizationProvider; +import org.apache.hadoop.hive.ql.session.SessionState; +import org.apache.hadoop.hive.shims.Utils; +import org.apache.hadoop.security.UserGroupInformation; +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +/** + * TestMetastoreClientSideAuthorizationProvider : Simple base test for Metastore client side + * Authorization Providers. By default, tests DefaultHiveAuthorizationProvider + */ +public class TestMetastoreClientSideAuthorizationProvider { + private HiveConf clientHiveConf; + private HiveMetaStoreClient msc; + private IDriver driver; + private UserGroupInformation ugi; + + @Before + public void setUp() throws Exception { + System.setProperty(HiveConf.ConfVars.METASTORE_PRE_EVENT_LISTENERS.varname, + "org.apache.hadoop.hive.ql.security.authorization.AuthorizationPreEventListener"); + + int port = MetaStoreTestUtils.startMetaStoreWithRetry(); + + clientHiveConf = new HiveConf(this.getClass()); + + // Turn on client-side authorization + clientHiveConf.setBoolVar(HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED,true); + clientHiveConf.set(HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER.varname, + getAuthorizationProvider()); + clientHiveConf.set(HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER.varname, + InjectableDummyAuthenticator.class.getName()); + clientHiveConf.set(HiveConf.ConfVars.HIVE_AUTHORIZATION_TABLE_OWNER_GRANTS.varname, ""); + clientHiveConf.setVar(HiveConf.ConfVars.HIVEMAPREDMODE, "nonstrict"); + clientHiveConf.setVar(HiveConf.ConfVars.METASTOREURIS, "thrift://localhost:" + port); + clientHiveConf.setIntVar(HiveConf.ConfVars.METASTORETHRIFTCONNECTIONRETRIES, 3); + clientHiveConf.set(HiveConf.ConfVars.HIVE_SUPPORT_CONCURRENCY.varname, "false"); + + clientHiveConf.set(HiveConf.ConfVars.PREEXECHOOKS.varname, ""); + clientHiveConf.set(HiveConf.ConfVars.POSTEXECHOOKS.varname, ""); + + ugi = Utils.getUGI(); + + SessionState.start(new CliSessionState(clientHiveConf)); + msc = new HiveMetaStoreClient(clientHiveConf); + driver = DriverFactory.newDriver(clientHiveConf); + } + + private String getAuthorizationProvider(){ + return DefaultHiveAuthorizationProvider.class.getName(); + } + + private void allowCreateDatabase(String userName) throws Exception { + driver.run("grant create to user " + userName); + } + + private void allowSelect(String userName) throws Exception { + driver.run("grant select to user " + userName); + } + + private void revokeSelect(String userName) throws Exception { + driver.run("revoke select from user " + userName); + } + + protected void allowCreateInDb(String dbName, String userName) throws Exception { + driver.run("grant create on database "+ dbName +" to user " + userName); + } + + private void allowSelectInDb(String dbName, String userName) throws Exception { + driver.run("grant select on database " + dbName + " to user " + userName); + } + + + private void disallowSelectDatabase(String dbName, String userName) throws Exception { + driver.run("revoke select on database " + dbName + " from user " + userName); + } + + @Test + public void testGetTableMeta() throws Exception { + String dbName1 = "database1"; + String tblName1 = "table1"; + + String userName = ugi.getUserName(); + allowCreateDatabase(userName); + allowSelect(userName); + driver.run("create database " + dbName1); + allowCreateInDb(dbName1, userName); + driver.run("use " + dbName1); + driver.run(String.format("create table %s (a string) partitioned by (b string)", tblName1)); + allowSelectInDb(dbName1, userName); + + String dbName2 = "database2"; + String tblName2 = "table2"; + driver.run("create database " + dbName2); + allowSelectInDb(dbName2, userName); + driver.run("use " + dbName2); + driver.run(String.format("create table %s (a string) partitioned by (b string)", tblName2)); + + List<TableMeta> tableMetas = msc.getTableMeta("*", "*", Lists.newArrayList()); + assertEquals(2, tableMetas.size()); + + revokeSelect(userName); + disallowSelectDatabase(dbName1, userName); + tableMetas = msc.getTableMeta("*", "*", Lists.newArrayList()); + assertEquals(1, tableMetas.size()); + assertEquals(dbName2, tableMetas.get(0).getDbName()); + assertEquals(tblName2, tableMetas.get(0).getTableName()); + + disallowSelectDatabase(dbName2, userName); + tableMetas = msc.getTableMeta("*", "*", Lists.newArrayList()); + assertEquals(0, tableMetas.size()); + } +} diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java index a2211a4..f849745 100644 --- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java @@ -3641,6 +3641,7 @@ public class HMSHandler extends FacebookBase implements IHMSHandler { t = getMS().getTableMeta(parsedDbName[CAT_NAME], parsedDbName[DB_NAME], tblNames, tblTypes); t = FilterUtils.filterTableMetasIfEnabled(isServerFilterEnabled, filterHook, parsedDbName[CAT_NAME], parsedDbName[DB_NAME], t); + t = filterReadableTables(parsedDbName[CAT_NAME], t); } catch (Exception e) { ex = e; throw newMetaException(e); @@ -5488,6 +5489,57 @@ public class HMSHandler extends FacebookBase implements IHMSHandler { } } + /** + * filters out the table meta for which read database access is not granted + * @param catName catalog name + * @param tableMetas list of table metas + * @return filtered list of table metas + * @throws RuntimeException + * @throws NoSuchObjectException + */ + private List<TableMeta> filterReadableTables(String catName, List<TableMeta> tableMetas) + throws RuntimeException, NoSuchObjectException { + List<TableMeta> finalT = new ArrayList<>(); + Map<String, Boolean> databaseNames = new HashMap(); + for (TableMeta tableMeta : tableMetas) { + String fullDbName = prependCatalogToDbName(catName, tableMeta.getDbName(), conf); + if (databaseNames.get(fullDbName) == null) { + boolean isExecptionThrown = false; + try { + fireReadDatabasePreEvent(fullDbName); + } catch (MetaException e) { + isExecptionThrown = true; + } + databaseNames.put(fullDbName, isExecptionThrown); + } + if (!databaseNames.get(fullDbName)) { + finalT.add(tableMeta); + } + } + return finalT; + } + + /** + * Fire a pre-event for read database operation, if there are any + * pre-event listeners registered + */ + private void fireReadDatabasePreEvent(final String name) + throws MetaException, RuntimeException, NoSuchObjectException { + if(preListeners.size() > 0) { + String[] parsedDbName = parseDbName(name, conf); + Database db = null; + try { + db = get_database_core(parsedDbName[CAT_NAME], parsedDbName[DB_NAME]); + if (db == null) { + throw new NoSuchObjectException("Database: " + name + " not found"); + } + } catch(MetaException | NoSuchObjectException e) { + throw new RuntimeException(e); + } + firePreEvent(new PreReadDatabaseEvent(db, this)); + } + } + @Override @Deprecated public Partition get_partition_with_auth(final String db_name,