Repository: sentry Updated Branches: refs/heads/master 436787cb6 -> 800584a16
SENTRY-1980: Move the hive-authz2 HMS client filtering implementation into the sentry-binding-hive module (Sergio Pena, reviewed by kalyan kumar kalvagadda, Na Li) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/800584a1 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/800584a1 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/800584a1 Branch: refs/heads/master Commit: 800584a164d99567dfb75b5f422efe50e690233b Parents: 436787c Author: Sergio Pena <[email protected]> Authored: Thu Oct 19 20:57:18 2017 -0500 Committer: Sergio Pena <[email protected]> Committed: Thu Oct 19 20:57:18 2017 -0500 ---------------------------------------------------------------------- .../hive/authz/DefaultSentryValidator.java | 472 +++++++++++++++++++ .../authz/SentryHiveAuthorizationValidator.java | 57 +++ .../hive/authz/SentryHiveAuthorizerFactory.java | 8 +- .../hive/authz/SentryHiveAuthorizerImpl.java | 66 +-- .../binding/util/SimpleSemanticAnalyzer.java | 373 +++++++++++++++ 5 files changed, 918 insertions(+), 58 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/800584a1/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryValidator.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryValidator.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryValidator.java new file mode 100644 index 0000000..d1f071e --- /dev/null +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/DefaultSentryValidator.java @@ -0,0 +1,472 @@ +/** + * 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.sentry.binding.hive.authz; + +import static org.apache.hadoop.hive.metastore.MetaStoreUtils.DEFAULT_DATABASE_NAME; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.ql.metadata.AuthorizationException; +import org.apache.hadoop.hive.ql.plan.HiveOperation; +import org.apache.hadoop.hive.ql.security.HiveAuthenticationProvider; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzContext; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType; +import org.apache.hadoop.hive.ql.session.SessionState; +import org.apache.sentry.binding.hive.SentryOnFailureHookContext; +import org.apache.sentry.binding.hive.SentryOnFailureHookContextImpl; +import org.apache.sentry.binding.hive.authz.HiveAuthzBinding.HiveHook; +import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveOperationScope; +import org.apache.sentry.binding.hive.conf.HiveAuthzConf; +import org.apache.sentry.binding.util.SentryAuthorizerUtil; +import org.apache.sentry.binding.util.SimpleSemanticAnalyzer; +import org.apache.sentry.core.common.Subject; +import org.apache.sentry.core.model.db.AccessURI; +import org.apache.sentry.core.model.db.Column; +import org.apache.sentry.core.model.db.DBModelAction; +import org.apache.sentry.core.model.db.DBModelAuthorizable; +import org.apache.sentry.core.model.db.DBModelAuthorizable.AuthorizableType; +import org.apache.sentry.core.model.db.Database; +import org.apache.sentry.core.model.db.Table; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class used to do authorization. Check if current user has privileges to do the operation. + */ +public class DefaultSentryValidator extends SentryHiveAuthorizationValidator { + + public static final Logger LOG = LoggerFactory.getLogger(DefaultSentryValidator.class); + + protected HiveConf conf; + protected HiveAuthzConf authzConf; + protected HiveAuthenticationProvider authenticator; + + public DefaultSentryValidator(HiveConf conf, HiveAuthzConf authzConf, + HiveAuthenticationProvider authenticator) throws Exception { + initilize(conf, authzConf, authenticator); + this.hiveHook = HiveHook.HiveServer2; + } + + public DefaultSentryValidator(HiveHook hiveHook, HiveConf conf, HiveAuthzConf authzConf, + HiveAuthenticationProvider authenticator) throws Exception { + initilize(conf, authzConf, authenticator); + this.hiveHook = hiveHook; + } + + /** + * initialize authenticator and hiveAuthzBinding. + */ + protected void initilize(HiveConf conf, HiveAuthzConf authzConf, + HiveAuthenticationProvider authenticator) throws Exception { + Preconditions.checkNotNull(conf, "HiveConf cannot be null"); + Preconditions.checkNotNull(authzConf, "HiveAuthzConf cannot be null"); + Preconditions.checkNotNull(authenticator, "Hive authenticator provider cannot be null"); + this.conf = conf; + this.authzConf = authzConf; + this.authenticator = authenticator; + } + + private HiveHook hiveHook; + + // all operations need to extend at DB scope + private static final Set<HiveOperation> EX_DB_ALL = Sets.newHashSet(HiveOperation.DROPDATABASE, + HiveOperation.CREATETABLE, HiveOperation.IMPORT, HiveOperation.DESCDATABASE, + HiveOperation.ALTERTABLE_RENAME, HiveOperation.LOCKDB, HiveOperation.UNLOCKDB); + // input operations need to extend at DB scope + private static final Set<HiveOperation> EX_DB_INPUT = Sets.newHashSet(HiveOperation.DROPDATABASE, + HiveOperation.DESCDATABASE, HiveOperation.ALTERTABLE_RENAME, HiveOperation.LOCKDB, + HiveOperation.UNLOCKDB); + + // all operations need to extend at Table scope + private static final Set<HiveOperation> EX_TB_ALL = Sets.newHashSet(HiveOperation.DROPTABLE, + HiveOperation.DROPVIEW, HiveOperation.DESCTABLE, HiveOperation.SHOW_TBLPROPERTIES, + HiveOperation.SHOWINDEXES, HiveOperation.ALTERTABLE_PROPERTIES, + HiveOperation.ALTERTABLE_SERDEPROPERTIES, HiveOperation.ALTERTABLE_CLUSTER_SORT, + HiveOperation.ALTERTABLE_FILEFORMAT, HiveOperation.ALTERTABLE_TOUCH, + HiveOperation.ALTERTABLE_ADDCOLS, HiveOperation.ALTERTABLE_REPLACECOLS, + HiveOperation.ALTERTABLE_RENAMEPART, HiveOperation.ALTERTABLE_ARCHIVE, + HiveOperation.ALTERTABLE_UNARCHIVE, HiveOperation.ALTERTABLE_SERIALIZER, + HiveOperation.ALTERTABLE_MERGEFILES, HiveOperation.ALTERTABLE_SKEWED, + HiveOperation.ALTERTABLE_DROPPARTS, HiveOperation.ALTERTABLE_ADDPARTS, + HiveOperation.ALTERTABLE_RENAME, HiveOperation.ALTERTABLE_LOCATION, + HiveOperation.ALTERVIEW_PROPERTIES, HiveOperation.ALTERPARTITION_FILEFORMAT, + HiveOperation.ALTERPARTITION_SERIALIZER, HiveOperation.ALTERPARTITION_MERGEFILES, + HiveOperation.ALTERPARTITION_LOCATION, HiveOperation.ALTERTBLPART_SKEWED_LOCATION, + HiveOperation.MSCK, HiveOperation.ALTERINDEX_REBUILD, HiveOperation.LOCKTABLE, + HiveOperation.UNLOCKTABLE, HiveOperation.SHOWCOLUMNS, HiveOperation.SHOW_TABLESTATUS, + HiveOperation.LOAD, HiveOperation.TRUNCATETABLE); + // input operations need to extend at Table scope + private static final Set<HiveOperation> EX_TB_INPUT = Sets.newHashSet(HiveOperation.DROPTABLE, + HiveOperation.DROPVIEW, HiveOperation.SHOW_TBLPROPERTIES, HiveOperation.SHOWINDEXES, + HiveOperation.ALTERINDEX_REBUILD, HiveOperation.LOCKTABLE, HiveOperation.UNLOCKTABLE, + HiveOperation.SHOW_TABLESTATUS); + private static final Set<HiveOperation> META_TB_INPUT = Sets.newHashSet(HiveOperation.DESCTABLE, + HiveOperation.SHOWCOLUMNS); + + /** + * Check if current user has privileges to perform given operation type hiveOpType on the given + * input and output objects + * + * @param hiveOpType + * @param inputHObjs + * @param outputHObjs + * @param context + * @throws + */ + @Override + public void checkPrivileges(HiveOperationType hiveOpType, List<HivePrivilegeObject> inputHObjs, + List<HivePrivilegeObject> outputHObjs, HiveAuthzContext context) + throws HiveAuthzPluginException, HiveAccessControlException { + if (LOG.isDebugEnabled()) { + String msg = + "Checking privileges for operation " + hiveOpType + " by user " + + authenticator.getUserName() + " on " + " input objects " + inputHObjs + + " and output objects " + outputHObjs + ". Context Info: " + context; + LOG.debug(msg); + } + + HiveOperation hiveOp = SentryAuthorizerUtil.convert2HiveOperation(hiveOpType.name()); + HiveAuthzPrivileges stmtAuthPrivileges = null; + if (HiveOperation.DESCTABLE.equals(hiveOp) && + !(context.getCommandString().contains("EXTENDED") || context.getCommandString().contains("FORMATTED")) ) { + stmtAuthPrivileges = HiveAuthzPrivilegesMap.getHiveAuthzPrivileges(HiveOperation.SHOWCOLUMNS); + } else { + stmtAuthPrivileges = HiveAuthzPrivilegesMap.getHiveAuthzPrivileges(hiveOp); + } + + HiveAuthzBinding hiveAuthzBinding = null; + try { + hiveAuthzBinding = getAuthzBinding(); + if (stmtAuthPrivileges == null) { + // We don't handle authorizing this statement + return; + } + + List<List<DBModelAuthorizable>> inputHierarchyList = + SentryAuthorizerUtil.convert2SentryPrivilegeList(hiveAuthzBinding.getAuthServer(), + inputHObjs); + List<List<DBModelAuthorizable>> outputHierarchyList = + SentryAuthorizerUtil.convert2SentryPrivilegeList(hiveAuthzBinding.getAuthServer(), + outputHObjs); + + // Workaround for metadata queries + addExtendHierarchy(hiveOp, stmtAuthPrivileges, inputHierarchyList, outputHierarchyList, + context.getCommandString(), hiveAuthzBinding); + + hiveAuthzBinding.authorize(hiveOp, stmtAuthPrivileges, + new Subject(authenticator.getUserName()), inputHierarchyList, outputHierarchyList); + } catch (AuthorizationException e) { + Database db = null; + Table tab = null; + if (outputHObjs != null) { + for (HivePrivilegeObject obj : outputHObjs) { + switch (obj.getType()) { + case DATABASE: + db = new Database(obj.getObjectName()); + break; + case TABLE_OR_VIEW: + db = new Database(obj.getDbname()); + tab = new Table(obj.getObjectName()); + break; + case PARTITION: + db = new Database(obj.getDbname()); + tab = new Table(obj.getObjectName()); + case LOCAL_URI: + case DFS_URI: + } + } + } + String permsRequired = ""; + SentryOnFailureHookContext hookCtx = + new SentryOnFailureHookContextImpl(context.getCommandString(), null, null, hiveOp, db, + tab, Collections.<AccessURI>emptyList(), null, + authenticator.getUserName(), context.getIpAddress(), e, authzConf); + SentryAuthorizerUtil.executeOnFailureHooks(hookCtx, authzConf); + for (String perm : hiveAuthzBinding.getLastQueryPrivilegeErrors()) { + permsRequired += perm + ";"; + } + SessionState.get().getConf().set(HiveAuthzConf.HIVE_SENTRY_AUTH_ERRORS, permsRequired); + String msg = + HiveAuthzConf.HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE + + "\n Required privileges for this query: " + permsRequired; + throw new HiveAccessControlException(msg, e); + } catch (Exception e) { + throw new HiveAuthzPluginException(e.getClass()+ ": " + e.getMessage(), e); + } finally { + if (hiveAuthzBinding != null) { + hiveAuthzBinding.close(); + } + } + + if ("true".equalsIgnoreCase(SessionState.get().getConf() + .get(HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION))) { + throw new HiveAccessControlException(HiveAuthzConf.HIVE_SENTRY_MOCK_ERROR + + " Mock query compilation aborted. Set " + HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION + + " to 'false' for normal query processing"); + } + } + + @VisibleForTesting + public HiveAuthzBinding getAuthzBinding() throws Exception { + return new HiveAuthzBinding(hiveHook, conf, authzConf); + } + + private void addExtendHierarchy(HiveOperation hiveOp, HiveAuthzPrivileges stmtAuthPrivileges, + List<List<DBModelAuthorizable>> inputHierarchyList, + List<List<DBModelAuthorizable>> outputHierarchyList, String command, + HiveAuthzBinding hiveAuthzBinding) throws HiveAuthzPluginException, + HiveAccessControlException { + String currDatabase = null; + switch (stmtAuthPrivileges.getOperationScope()) { + case SERVER: + // validate server level privileges if applicable. Eg create UDF,register jar etc .. + List<DBModelAuthorizable> serverHierarchy = new ArrayList<DBModelAuthorizable>(); + serverHierarchy.add(hiveAuthzBinding.getAuthServer()); + inputHierarchyList.add(serverHierarchy); + break; + case DATABASE: + // workaround for metadata queries. + if (EX_DB_ALL.contains(hiveOp)) { + SimpleSemanticAnalyzer analyzer = new SimpleSemanticAnalyzer(hiveOp, command); + currDatabase = analyzer.getCurrentDb(); + + List<DBModelAuthorizable> externalAuthorizableHierarchy = + new ArrayList<DBModelAuthorizable>(); + externalAuthorizableHierarchy.add(hiveAuthzBinding.getAuthServer()); + externalAuthorizableHierarchy.add(new Database(currDatabase)); + + if (EX_DB_INPUT.contains(hiveOp)) { + inputHierarchyList.add(externalAuthorizableHierarchy); + } else { + outputHierarchyList.add(externalAuthorizableHierarchy); + } + } + break; + case TABLE: + case COLUMN: + // workaround for drop table/view. + if (EX_TB_ALL.contains(hiveOp)) { + SimpleSemanticAnalyzer analyzer = new SimpleSemanticAnalyzer(hiveOp, command); + currDatabase = analyzer.getCurrentDb(); + String currTable = analyzer.getCurrentTb(); + + List<DBModelAuthorizable> externalAuthorizableHierarchy = + new ArrayList<DBModelAuthorizable>(); + externalAuthorizableHierarchy.add(hiveAuthzBinding.getAuthServer()); + externalAuthorizableHierarchy.add(new Database(currDatabase)); + externalAuthorizableHierarchy.add(new Table(currTable)); + + if (EX_TB_INPUT.contains(hiveOp)) { + inputHierarchyList.add(externalAuthorizableHierarchy); + } else if (META_TB_INPUT.contains(hiveOp)) { + externalAuthorizableHierarchy.add(Column.SOME); + inputHierarchyList.add(externalAuthorizableHierarchy); + } else { + outputHierarchyList.add(externalAuthorizableHierarchy); + } + } + break; + case FUNCTION: + if (hiveOp.equals(HiveOperation.CREATEFUNCTION)) { + SimpleSemanticAnalyzer analyzer = new SimpleSemanticAnalyzer(hiveOp, command); + currDatabase = analyzer.getCurrentDb(); + String udfClassName = analyzer.getCurrentTb(); + try { + CodeSource udfSrc = Class.forName(udfClassName).getProtectionDomain().getCodeSource(); + if (udfSrc == null) { + throw new HiveAuthzPluginException("Could not resolve the jar for UDF class " + + udfClassName); + } + String udfJar = udfSrc.getLocation().getPath(); + if (udfJar == null || udfJar.isEmpty()) { + throw new HiveAuthzPluginException("Could not find the jar for UDF class " + + udfClassName + "to validate privileges"); + } + AccessURI udfURI = SentryAuthorizerUtil.parseURI(udfSrc.getLocation().toString(), true); + List<DBModelAuthorizable> udfUriHierarchy = new ArrayList<DBModelAuthorizable>(); + udfUriHierarchy.add(hiveAuthzBinding.getAuthServer()); + udfUriHierarchy.add(udfURI); + inputHierarchyList.add(udfUriHierarchy); + } catch (Exception e) { + throw new HiveAuthzPluginException("Error retrieving udf class", e); + } + } + break; + case CONNECT: + /* + * The 'CONNECT' is an implicit privilege scope currently used for - USE <db> It's allowed + * when the user has any privilege on the current database. For application backward + * compatibility, we allow (optional) implicit connect permission on 'default' db. + */ + List<DBModelAuthorizable> connectHierarchy = new ArrayList<DBModelAuthorizable>(); + connectHierarchy.add(hiveAuthzBinding.getAuthServer()); + if (hiveOp.equals(HiveOperation.SWITCHDATABASE)) { + currDatabase = command.split(" ")[1]; + } + // by default allow connect access to default db + Table currTbl = Table.ALL; + Database currDB = new Database(currDatabase); + Column currCol = Column.ALL; + if (DEFAULT_DATABASE_NAME.equalsIgnoreCase(currDatabase) && "false" + .equalsIgnoreCase(authzConf.get( + HiveAuthzConf.AuthzConfVars.AUTHZ_RESTRICT_DEFAULT_DB.getVar(), "false"))) { + currDB = Database.ALL; + currTbl = Table.SOME; + } + + connectHierarchy.add(currDB); + connectHierarchy.add(currTbl); + connectHierarchy.add(currCol); + + inputHierarchyList.add(connectHierarchy); + break; + } + } + + @Override + public List<HivePrivilegeObject> filterListCmdObjects(List<HivePrivilegeObject> listObjs, + HiveAuthzContext context) { + if (listObjs != null && listObjs.size() >= 1) { + HivePrivilegeObjectType pType = listObjs.get(0).getType(); + HiveAuthzBinding hiveAuthzBinding = null; + try { + switch (pType) { + case DATABASE: + hiveAuthzBinding = getAuthzBinding(); + listObjs = filterShowDatabases(listObjs, authenticator.getUserName(), hiveAuthzBinding); + break; + case TABLE_OR_VIEW: + hiveAuthzBinding = getAuthzBinding(); + listObjs = filterShowTables(listObjs, authenticator.getUserName(), hiveAuthzBinding); + break; + } + } catch (Exception e) { + LOG.warn(e.getMessage(),e); + } finally { + if (hiveAuthzBinding != null) { + hiveAuthzBinding.close(); + } + } + } + return listObjs; + } + + private List<HivePrivilegeObject> filterShowTables(List<HivePrivilegeObject> listObjs, + String userName, HiveAuthzBinding hiveAuthzBinding) { + List<HivePrivilegeObject> filteredResult = new ArrayList<HivePrivilegeObject>(); + Subject subject = new Subject(userName); + HiveAuthzPrivileges tableMetaDataPrivilege = + new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge(AuthorizableType.Column, + EnumSet.of(DBModelAction.SELECT, DBModelAction.INSERT)) + .setOperationScope(HiveOperationScope.TABLE) + .setOperationType( + HiveAuthzPrivileges.HiveOperationType.INFO) + .build(); + + for (HivePrivilegeObject obj : listObjs) { + // if user has privileges on table, add to filtered list, else discard + Table table = new Table(obj.getObjectName()); + Database database; + database = new Database(obj.getDbname()); + + List<List<DBModelAuthorizable>> inputHierarchy = new ArrayList<List<DBModelAuthorizable>>(); + List<List<DBModelAuthorizable>> outputHierarchy = new ArrayList<List<DBModelAuthorizable>>(); + List<DBModelAuthorizable> externalAuthorizableHierarchy = + new ArrayList<DBModelAuthorizable>(); + externalAuthorizableHierarchy.add(hiveAuthzBinding.getAuthServer()); + externalAuthorizableHierarchy.add(database); + externalAuthorizableHierarchy.add(table); + externalAuthorizableHierarchy.add(Column.ALL); + inputHierarchy.add(externalAuthorizableHierarchy); + + try { + hiveAuthzBinding.authorize(HiveOperation.SHOWTABLES, tableMetaDataPrivilege, subject, + inputHierarchy, outputHierarchy); + filteredResult.add(obj); + } catch (AuthorizationException e) { + // squash the exception, user doesn't have privileges, so the table is + // not added to + // filtered list. + } + } + return filteredResult; + } + + private List<HivePrivilegeObject> filterShowDatabases(List<HivePrivilegeObject> listObjs, + String userName, HiveAuthzBinding hiveAuthzBinding) { + List<HivePrivilegeObject> filteredResult = new ArrayList<HivePrivilegeObject>(); + Subject subject = new Subject(userName); + HiveAuthzPrivileges anyPrivilege = + new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge( + AuthorizableType.Column, + EnumSet.of(DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, + DBModelAction.LOCK)) + .setOperationScope(HiveOperationScope.CONNECT) + .setOperationType( + HiveAuthzPrivileges.HiveOperationType.QUERY) + .build(); + + for (HivePrivilegeObject obj : listObjs) { + // if user has privileges on database, add to filtered list, else discard + Database database = null; + + // if default is not restricted, continue + if (DEFAULT_DATABASE_NAME.equalsIgnoreCase(obj.getObjectName()) + && "false".equalsIgnoreCase(hiveAuthzBinding.getAuthzConf().get( + HiveAuthzConf.AuthzConfVars.AUTHZ_RESTRICT_DEFAULT_DB.getVar(), "false"))) { + filteredResult.add(obj); + continue; + } + + database = new Database(obj.getObjectName()); + + List<List<DBModelAuthorizable>> inputHierarchy = new ArrayList<List<DBModelAuthorizable>>(); + List<List<DBModelAuthorizable>> outputHierarchy = new ArrayList<List<DBModelAuthorizable>>(); + List<DBModelAuthorizable> externalAuthorizableHierarchy = + new ArrayList<DBModelAuthorizable>(); + externalAuthorizableHierarchy.add(hiveAuthzBinding.getAuthServer()); + externalAuthorizableHierarchy.add(database); + externalAuthorizableHierarchy.add(Table.ALL); + externalAuthorizableHierarchy.add(Column.ALL); + inputHierarchy.add(externalAuthorizableHierarchy); + + try { + hiveAuthzBinding.authorize(HiveOperation.SHOWDATABASES, anyPrivilege, subject, + inputHierarchy, outputHierarchy); + filteredResult.add(obj); + } catch (AuthorizationException e) { + // squash the exception, user doesn't have privileges, so the table is + // not added to + // filtered list. + } + } + return filteredResult; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/800584a1/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizationValidator.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizationValidator.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizationValidator.java new file mode 100644 index 0000000..8e42aaf --- /dev/null +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizationValidator.java @@ -0,0 +1,57 @@ +/** + * 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.sentry.binding.hive.authz; + +import java.util.List; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizationValidator; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzContext; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject; + +/** + * This class used to do authorization validate. Check if current user has privileges to do the + * operation and filter the select results. + */ +public abstract class SentryHiveAuthorizationValidator implements HiveAuthorizationValidator { + + /** + * Check if current user has privileges to perform given operation type hiveOpType on the given + * input and output objects. + * + * @param hiveOpType + * @param inputHObjs + * @param outputHObjs + * @param context + * @throws HiveAuthzPluginException, HiveAccessControlException + */ + @Override + public abstract void checkPrivileges(HiveOperationType hiveOpType, + List<HivePrivilegeObject> inputHObjs, List<HivePrivilegeObject> outputHObjs, + HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException; + + + /** + * Filter the select results according current user's permission. remove the object which current + * user do not have any privilege on it. + * + * @param listObjs + * @param context + */ + @Override + public abstract List<HivePrivilegeObject> filterListCmdObjects( + List<HivePrivilegeObject> listObjs, HiveAuthzContext context); +} http://git-wip-us.apache.org/repos/asf/sentry/blob/800584a1/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerFactory.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerFactory.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerFactory.java index 76a757a..db8e428 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerFactory.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerFactory.java @@ -47,14 +47,20 @@ public class SentryHiveAuthorizerFactory implements HiveAuthorizerFactory { HiveAuthzSessionContext sessionContext = applyTestSettings(ctx, conf); SentryHiveAccessController accessController; + SentryHiveAuthorizationValidator authValidator; try { accessController = new DefaultSentryAccessController(conf, authzConf, hiveAuthenticator, sessionContext); + + authValidator = + new DefaultSentryValidator(conf, authzConf, hiveAuthenticator); } catch (Exception e) { throw new HiveAuthzPluginException(e); } - return new SentryHiveAuthorizerImpl(accessController); + + + return new SentryHiveAuthorizerImpl(accessController, authValidator); } private HiveAuthzSessionContext applyTestSettings(HiveAuthzSessionContext ctx, HiveConf conf) { http://git-wip-us.apache.org/repos/asf/sentry/blob/800584a1/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerImpl.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerImpl.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerImpl.java index 4aff76f..1596bce 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerImpl.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryHiveAuthorizerImpl.java @@ -16,7 +16,6 @@ */ package org.apache.sentry.binding.hive.authz; -import java.util.ArrayList; import java.util.List; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.ql.exec.SentryHivePrivilegeObjectDesc; @@ -36,7 +35,6 @@ import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObje import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType; import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveRoleGrant; import org.apache.sentry.binding.hive.SentryHivePrivilegeObject; -import org.apache.sentry.binding.metastore.SentryMetaStoreFilterHook; /** * This is a HiveAuthorizer implementation, and it is used by HiveServer2 to check privileges @@ -49,14 +47,14 @@ import org.apache.sentry.binding.metastore.SentryMetaStoreFilterHook; */ public class SentryHiveAuthorizerImpl extends AbstractHiveAuthorizer { private SentryHiveAccessController accessController; + private SentryHiveAuthorizationValidator authValidator; static private HiveAuthorizationTranslator hiveTranslator = new SentryHiveAuthorizationTranslator(); - private SentryMetaStoreFilterHook filterHook; - - public SentryHiveAuthorizerImpl(SentryHiveAccessController accessController) { + public SentryHiveAuthorizerImpl(SentryHiveAccessController accessController, + SentryHiveAuthorizationValidator authValidator) { this.accessController = accessController; - this.filterHook = new SentryMetaStoreFilterHook(null); + this.authValidator = authValidator; } @Override @@ -123,24 +121,16 @@ public class SentryHiveAuthorizerImpl extends AbstractHiveAuthorizer { public void checkPrivileges(HiveOperationType hiveOpType, List<HivePrivilegeObject> inputsHObjs, List<HivePrivilegeObject> outputHObjs, HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException { - // Nothing to do there. Privileges are checked on the Semantic hooks + // The privileges for a query are checked on the Semantic hooks (HiveAuthzBindingHook) instead + // because of lack of information that Hive pass as parameters on this method. + // TODO: This will be fixed as part of SENTRY-1957 + // authValidator.checkPrivileges(hiveOpType, inputsHObjs, outputHObjs, context); } @Override public List<HivePrivilegeObject> filterListCmdObjects(List<HivePrivilegeObject> listObjs, HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException { - if (listObjs == null || listObjs.size() == 0) { - return listObjs; - } - - switch (listObjs.get(0).getType()) { - case DATABASE: - return filterDbs(listObjs); - case TABLE_OR_VIEW: - return filterTables(listObjs); - default: - return listObjs; - } + return authValidator.filterListCmdObjects(listObjs, context); } @Override @@ -175,44 +165,6 @@ public class SentryHiveAuthorizerImpl extends AbstractHiveAuthorizer { return hiveTranslator; } - private List<HivePrivilegeObject> filterDbs(List<HivePrivilegeObject> listObjs) { - List<String> dbList = new ArrayList<>(listObjs.size()); - for (HivePrivilegeObject o : listObjs) { - dbList.add(o.getDbname()); - } - - List<String> filterDbList = filterHook.filterDatabases(dbList); - List<HivePrivilegeObject> filterObjs = new ArrayList<>(filterDbList.size()); - for (String db : filterDbList) { - filterObjs.add(new HivePrivilegeObject(HivePrivilegeObjectType.DATABASE, db, db)); - } - - return filterObjs; - } - - private List<HivePrivilegeObject> filterTables(List<HivePrivilegeObject> listObjs) { - if (listObjs == null || listObjs.size() == 0) { - return listObjs; - } - - List<String> tableList = new ArrayList<>(listObjs.size()); - for (HivePrivilegeObject o : listObjs) { - tableList.add(o.getObjectName()); - } - - String db = listObjs.get(0).getDbname(); - - List<String> filterTableList = - filterHook.filterTableNames(db, tableList); - - List<HivePrivilegeObject> filterObjs = new ArrayList<>(filterTableList.size()); - for (String table : filterTableList) { - filterObjs.add(new HivePrivilegeObject(HivePrivilegeObjectType.TABLE_OR_VIEW, db, table)); - } - - return filterObjs; - } - protected static HivePrivilegeObjectType getPrivObjectType( SentryHivePrivilegeObjectDesc privSubjectDesc) { if (privSubjectDesc.getObject() == null) { http://git-wip-us.apache.org/repos/asf/sentry/blob/800584a1/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/util/SimpleSemanticAnalyzer.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/util/SimpleSemanticAnalyzer.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/util/SimpleSemanticAnalyzer.java new file mode 100644 index 0000000..09fcd38 --- /dev/null +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/util/SimpleSemanticAnalyzer.java @@ -0,0 +1,373 @@ +/** + * 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.sentry.binding.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.hadoop.hive.ql.plan.HiveOperation; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException; +import org.apache.hadoop.hive.ql.session.SessionState; +import org.apache.sentry.core.model.db.Table; + +/** + * Currently hive complier doesn't create read/write entities for some operations, e.g. create + * table, drop table. This class is a simple semantic analyzer using regex, it is a workaround + * approach to extract db_name and tb_name from those operations. + * + * TODO: This will be removed as part of SENTRY-1957 + */ +public class SimpleSemanticAnalyzer { + private String currentDb; + private String currentTb; + + /** + * CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name ... + */ + private static final String CREATE_TABLE_REGEX = "^(CREATE)\\s+" + "(TEMPORARY\\s+)?" + + "(EXTERNAL\\s+)?" + "TABLE\\s+" + "(IF\\s+NOT\\s+EXISTS\\s+)?" + "([A-Za-z0-9._]+)"; + + /** + * DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE]; + */ + private static final String DROP_DB_REGEX = "^DROP\\s+" + "(DATABASE|SCHEMA)\\s+" + + "(IF\\s+EXISTS\\s+)?" + "([A-Za-z0-9_]+)"; + + /** + * DROP TABLE [IF EXISTS] table_name; + */ + private static final String DROP_TABLE_REGEX = "^DROP\\s+" + "TABLE\\s+" + "(IF\\s+EXISTS\\s+)?" + + "([A-Za-z0-9._]+)"; + + /** + * DROP VIEW [IF EXISTS] view_name; + */ + private static final String DROP_VIEW_REGEX = "^DROP\\s+" + "VIEW\\s+" + "(IF\\s+EXISTS\\s+)?" + + "([A-Za-z0-9_].+)"; + + /** + * DESCRIBE DATABASE|SCHEMA [EXTENDED] db_name; + */ + private static final String DESCRIBE_DB_REGEX = "^DESCRIBE\\s+" + "(DATABASE|SCHEMA)\\s+" + + "(EXTENDED\\s+)?" + "([A-Za-z0-9_]+)"; + + /** + * DESCRIBE [EXTENDED|FORMATTED] [db_name.]table_name[.col_name ( [.field_name] | [.'$elem$'] | + * [.'$key$'] | [.'$value$'] )* ]; + */ + private static final String DESCRIBE_TABLE_REGEX = "^DESCRIBE\\s+" + + "((EXTENDED|FORMATTED)\\s+)?" + "([A-Za-z0-9._]+)"; + + /** + * SHOW [FORMATTED] (INDEX|INDEXES) ON table_with_index [(FROM|IN) db_name]; + */ + private static final String SHOW_INDEX_REGEX = "^SHOW\\s+" + "(FORMATTED\\s+)?" + + "(INDEX|INDEXES)\\s+" + "ON\\s+" + "([A-Za-z0-9._]+)\\s*" + + "((FROM|IN)\\s+([A-Za-z0-9_]+))?"; + + /** + * SHOW TBLPROPERTIES tblname; + */ + private static final String SHOW_TBLPROPERTIES_REGEX = "^SHOW\\s+" + "TBLPROPERTIES\\s+" + + "([A-Za-z0-9._]+)"; + + /** + * ALTER TABLE table_name ... + */ + private static final String ALTER_TABLE_REGEX = "^ALTER\\s+" + "TABLE\\s+" + "([A-Za-z0-9._]+)"; + + /** + * ALTER VIEW view_name ... + */ + private static final String ALTER_VIEW_REGEX = "^ALTER\\s+" + "VIEW\\s+" + "([A-Za-z0-9._]+)"; + + /** + * MSCK REPAIR TABLE table_name; + */ + private static final String MSCK_REGEX = "^MSCK\\s+" + "REPAIR\\s" + "TABLE\\s" + + "([A-Za-z0-9._]+)"; + + /** + * ALTER INDEX index_name ON table_name [PARTITION partition_spec] REBUILD; + */ + private static final String ALTER_INDEX_REGEX = "^ALTER\\s+" + "INDEX\\s+" + + "([A-Za-z0-9_]+)\\s+" + "ON\\s" + "([A-Za-z0-9._]+)"; + + /** + * CREATE FUNCTION [db_name.]function_name AS class_name [USING JAR|FILE|ARCHIVE 'file_uri' [, + * JAR|FILE|ARCHIVE 'file_uri'] ]; + */ + private static final String CREATE_FUNCTION_REGEX = "^CREATE\\s+" + "(TEMPORARY\\s+)?" + + "FUNCTION\\s+" + "([A-Za-z0-9._]+)\\s+" + "AS\\s" + "([A-Za-z0-9._']+)"; + + /** + * SHOW COLUMNS FROM table_name + */ + private static final String SHOWCOLUMNS = "^SHOW\\s+" + "COLUMNS\\s+" + "(FROM|IN)\\s+" + + "([A-Za-z0-9._]+)"; + + private static final String SHOW_TABLESTATUS = "^SHOW\\s+" + "TABLE\\s+" + "EXTENDED\\s+" + "IN\\s+" + + "([A-Za-z0-9._]+)"; + + private static final String LOAD = "^LOAD\\s+" + "DATA\\s+" + "(LOCAL\\s+)?" + "INPATH\\s+" + + "([A-Za-z0-9._':///-]+)" +"\\s" + "(OVERWRITE\\s+)?" + "INTO\\s" + "TABLE\\s" + "([A-Za-z0-9._]+)"; + + /** + * LOCK DATABASE dbname; + */ + private static final String LOCKDB = "^LOCK\\s+" + "DATABASE\\s+" + "([A-Za-z0-9._]+)"; + + /** + * UNLOCK DATABASE dbname; + */ + private static final String UNLOCKDB = "^UNLOCK\\s+" + "DATABASE\\s+" + "([A-Za-z0-9._]+)"; + + /** + * LOCK TABLE tblname; + */ + private static final String LOCKTABLE = "^LOCK\\s+" + "TABLE\\s+" + "([A-Za-z0-9._]+)"; + + /** + * UNLOCK TABLE tblname; + */ + private static final String UNLOCKTABLE = "^UNLOCK\\s+" + "TABLE\\s+" + "([A-Za-z0-9._]+)"; + + /** + * TRUNCATE TABLE tblname; + */ + private static final String TRUNCATETABLE = "^TRUNCATE\\s+" + "TABLE\\s+" + "([A-Za-z0-9._]+)"; + + private static Map<HiveOperation, String> OP_REGEX_MAP = new HashMap<HiveOperation, String>(); + static { + // database metadata + OP_REGEX_MAP.put(HiveOperation.DROPDATABASE, DROP_DB_REGEX); + OP_REGEX_MAP.put(HiveOperation.DESCDATABASE, DESCRIBE_DB_REGEX); + + // table metadata + OP_REGEX_MAP.put(HiveOperation.CREATETABLE, CREATE_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.DROPTABLE, DROP_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.DROPVIEW, DROP_VIEW_REGEX); + OP_REGEX_MAP.put(HiveOperation.DESCTABLE, DESCRIBE_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.SHOW_TBLPROPERTIES, SHOW_TBLPROPERTIES_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_PROPERTIES, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_SERDEPROPERTIES, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_CLUSTER_SORT, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_FILEFORMAT, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_TOUCH, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_RENAMECOL, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_ADDCOLS, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_REPLACECOLS, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_RENAMEPART, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_ARCHIVE, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_UNARCHIVE, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_SERIALIZER, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_MERGEFILES, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_SKEWED, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_DROPPARTS, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_ADDPARTS, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_RENAME, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTABLE_LOCATION, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERPARTITION_FILEFORMAT, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERPARTITION_SERDEPROPERTIES, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERPARTITION_SERIALIZER, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERPARTITION_MERGEFILES, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERPARTITION_LOCATION, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERTBLPART_SKEWED_LOCATION, ALTER_TABLE_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERVIEW_PROPERTIES, ALTER_VIEW_REGEX); + OP_REGEX_MAP.put(HiveOperation.MSCK, MSCK_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERINDEX_REBUILD, ALTER_INDEX_REGEX); + OP_REGEX_MAP.put(HiveOperation.ALTERINDEX_PROPS, ALTER_INDEX_REGEX); + OP_REGEX_MAP.put(HiveOperation.LOCKDB, LOCKDB); + OP_REGEX_MAP.put(HiveOperation.UNLOCKDB, UNLOCKDB); + OP_REGEX_MAP.put(HiveOperation.LOCKTABLE, LOCKTABLE); + OP_REGEX_MAP.put(HiveOperation.UNLOCKTABLE, UNLOCKTABLE); + OP_REGEX_MAP.put(HiveOperation.SHOWCOLUMNS, SHOWCOLUMNS); + OP_REGEX_MAP.put(HiveOperation.SHOW_TABLESTATUS, SHOW_TABLESTATUS); + OP_REGEX_MAP.put(HiveOperation.TRUNCATETABLE, TRUNCATETABLE); + } + + public SimpleSemanticAnalyzer(HiveOperation hiveOp, String cmd) throws HiveAuthzPluginException { + currentDb = SessionState.get().getCurrentDatabase(); + parse(hiveOp, cmd); + } + + private void parse(HiveOperation hiveOp, String cmd) throws HiveAuthzPluginException { + switch (hiveOp) { + case DROPDATABASE: + case DESCDATABASE: + case LOCKDB: + case UNLOCKDB: + parseDbMeta(cmd, OP_REGEX_MAP.get(hiveOp)); + break; + case DESCTABLE: + case CREATETABLE: + case DROPTABLE: + case DROPVIEW: + case SHOW_TBLPROPERTIES: + // alter table + case ALTERTABLE_PROPERTIES: + case ALTERTABLE_SERDEPROPERTIES: + case ALTERTABLE_CLUSTER_SORT: + case ALTERTABLE_FILEFORMAT: + case ALTERTABLE_TOUCH: + case ALTERTABLE_RENAMECOL: + case ALTERTABLE_ADDCOLS: + case ALTERTABLE_REPLACECOLS: + case ALTERTABLE_RENAMEPART: + case ALTERTABLE_ARCHIVE: + case ALTERTABLE_UNARCHIVE: + case ALTERTABLE_SERIALIZER: + case ALTERTABLE_MERGEFILES: + case ALTERTABLE_SKEWED: + case ALTERTABLE_DROPPARTS: + case ALTERTABLE_ADDPARTS: + case ALTERTABLE_RENAME: + case ALTERTABLE_LOCATION: + // alter view + case ALTERVIEW_PROPERTIES: + // alter partition + case ALTERPARTITION_FILEFORMAT: + case ALTERPARTITION_SERDEPROPERTIES: + case ALTERPARTITION_SERIALIZER: + case ALTERPARTITION_MERGEFILES: + case ALTERPARTITION_LOCATION: + case ALTERTBLPART_SKEWED_LOCATION: + // MSCK + case MSCK: + // alter index + case ALTERINDEX_REBUILD: + case ALTERINDEX_PROPS: + case LOCKTABLE: + case UNLOCKTABLE: + case SHOWCOLUMNS: + case TRUNCATETABLE: + parseTableMeta(cmd, OP_REGEX_MAP.get(hiveOp)); + break; + case SHOWINDEXES: + parseShowIndex(cmd, SHOW_INDEX_REGEX); + break; + case CREATEFUNCTION: + parseFunction(cmd, CREATE_FUNCTION_REGEX); + break; + case SHOW_TABLESTATUS: + parseTableExtend(cmd, SHOW_TABLESTATUS); + break; + case LOAD: + parseLoadTable(cmd, LOAD); + break; + default: + break; + } + } + + private void parseLoadTable(String cmd, String load) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(load, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + String tbName = matcher.group(matcher.groupCount()); + extractDbAndTb(tbName.trim()); + } else { + throw new HiveAuthzPluginException("this command " + cmd + " does not match the table meta grammar"); + } + } + + private void parseTableExtend(String cmd, String showTablestatus) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(showTablestatus, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + String dbName = matcher.group(matcher.groupCount()); + currentDb = dbName; + currentTb = Table.SOME.getName(); + } else { + throw new HiveAuthzPluginException("this command " + cmd + " does not match the table meta grammar"); + } + } + + private void extractDbAndTb(String tableName) { + if (tableName.contains(".")) { + String[] tb = tableName.split("\\."); + currentDb = tb[0]; + currentTb = tb[1]; + } else { + currentDb = SessionState.get().getCurrentDatabase(); + currentTb = tableName; + } + } + + private void parseDbMeta(String cmd, String regex) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + currentDb = matcher.group(matcher.groupCount()); + } else { + throw new HiveAuthzPluginException("this command " + cmd + + " does not match the database meta grammar"); + } + } + + private void parseTableMeta(String cmd, String regex) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + String tbName = matcher.group(matcher.groupCount()); + extractDbAndTb(tbName.trim()); + } else { + throw new HiveAuthzPluginException("this command " + cmd + " does not match the table meta grammar"); + } + } + + private void parseShowIndex(String cmd, String regex) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + String dbName = matcher.group(matcher.groupCount()); + String tbName = matcher.group(3); + if (dbName != null) { + currentDb = dbName; + currentTb = tbName; + } else { + extractDbAndTb(tbName); + } + } else { + throw new HiveAuthzPluginException("this command " + cmd + " does not match the show index grammar"); + } + } + + private void parseFunction(String cmd, String regex) throws HiveAuthzPluginException { + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(cmd); + if (matcher.find()) { + String udfClass = matcher.group(matcher.groupCount()); + if (udfClass.contains("'")) { + currentTb = udfClass.split("'")[1]; + } else { + currentTb = udfClass; + } + } else { + throw new HiveAuthzPluginException("this command " + cmd + + " does not match the create function grammar"); + } + } + + public String getCurrentDb() { + return currentDb; + } + + public String getCurrentTb() { + return currentTb; + } + +}
