| /* |
| * 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.collect.Lists; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.List; |
| import org.apache.hadoop.hbase.util.Strings; |
| import org.apache.hadoop.hive.ql.metadata.AuthorizationException; |
| import org.apache.hadoop.hive.ql.plan.HiveOperation; |
| import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveOperationScope; |
| import org.apache.sentry.binding.hive.authz.HiveAuthzPrivileges.HiveOperationType; |
| import org.apache.sentry.binding.hive.conf.HiveAuthzConf; |
| import org.apache.sentry.core.common.Subject; |
| 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; |
| |
| /** |
| * This class uses Sentry authorization to filter a list of HMS metadata objects (or authorization |
| * objects) based on the Sentry privileges that a user is part of. The methods are commonly used |
| * by the Sentry/HMS binding implementations to get a list of objects that a user is allowed to |
| * see. |
| */ |
| public class MetastoreAuthzObjectFilter<T> { |
| /** |
| * This interface is used to extract information of an object to be filtered. |
| * @param <T> |
| */ |
| public interface ObjectExtractor<T> { |
| String getDatabaseName(T t); |
| String getTableName(T t); |
| |
| } |
| |
| private final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() |
| .addInputObjectPriviledge( |
| AuthorizableType.Column, |
| EnumSet.of( |
| DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, |
| DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, |
| DBModelAction.LOCK)) |
| .addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.SELECT)) |
| .setOperationScope(HiveOperationScope.CONNECT) |
| .setOperationType(HiveOperationType.QUERY) |
| .build(); |
| |
| private final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() |
| .addInputObjectPriviledge( |
| AuthorizableType.Column, |
| EnumSet.of( |
| DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, |
| DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) |
| .setOperationScope(HiveOperationScope.TABLE) |
| .setOperationType( |
| HiveAuthzPrivileges.HiveOperationType.INFO) |
| .build(); |
| |
| private final boolean DEFAULT_DATABASE_RESTRICTED; |
| private final DBModelAuthorizable AUTH_SERVER; |
| private HiveAuthzBinding authzBinding; |
| private ObjectExtractor extractor; |
| |
| public MetastoreAuthzObjectFilter(HiveAuthzBinding authzBinding, ObjectExtractor extractor) { |
| this.authzBinding = authzBinding; |
| this.extractor = extractor; |
| this.AUTH_SERVER = authzBinding.getAuthServer(); |
| this.DEFAULT_DATABASE_RESTRICTED = authzBinding.getAuthzConf() |
| .getBoolean(HiveAuthzConf.AuthzConfVars.AUTHZ_RESTRICT_DEFAULT_DB.getVar(), false); |
| } |
| |
| /** |
| * Filter a list of {@code dbNames} objects based on the authorization privileges of {@code subject}. |
| * |
| * @param username The username to request authorization from. |
| * @param dbNames A list of databases that must be filtered based on the user privileges. |
| * @return A list of database objects filtered by the privileges of the user. If a null value is |
| * passed as {@code dbNames}, then an empty list is returned. |
| */ |
| public List<T> filterDatabases(String username, List<T> dbNames) { |
| if (dbNames == null) { |
| return Collections.emptyList(); |
| } |
| |
| List<T> filteredDatabases = Lists.newArrayList(); |
| for (T dbName : dbNames) { |
| String objName = extractor.getDatabaseName(dbName); |
| if (Strings.isEmpty(objName) || authorizeDatabase(username, objName)) { |
| filteredDatabases.add(dbName); |
| } |
| } |
| |
| return filteredDatabases; |
| } |
| |
| /** |
| * Filter a list of {@code tableNames} objects based on the authorization privileges of {@code subject}. |
| * |
| * @param username The username to request authorization from. |
| * @param tables A list of tables that must be filtered based on the user privileges. |
| * @return A list of tables objects filtered by the privileges of the user. If a null value is |
| * passed as {@code tableNames}, then an empty list is returned. |
| */ |
| public List<T> filterTables(String username, List<T> tables) { |
| if (tables == null) { |
| return Collections.emptyList(); |
| } |
| |
| List<T> filteredTables = Lists.newArrayList(); |
| for (T table : tables) { |
| String dbName = extractor.getDatabaseName(table); |
| String tableName = extractor.getTableName(table); |
| if (Strings.isEmpty(dbName) || authorizeTable(username, dbName, tableName)) { |
| filteredTables.add(table); |
| } |
| } |
| |
| return filteredTables; |
| } |
| |
| /** |
| * Checks if a database is authorized to be accessed by the specific user. |
| * @return True if it is authorized, false otherwise. |
| */ |
| private boolean authorizeDatabase(String username, String dbName) { |
| if (!DEFAULT_DATABASE_RESTRICTED && dbName.equalsIgnoreCase(DEFAULT_DATABASE_NAME)) { |
| return true; |
| } |
| |
| Database database = new Database(dbName); |
| List<DBModelAuthorizable> authorizable = Arrays.asList( |
| AUTH_SERVER, database, Table.ALL, Column.ALL |
| ); |
| |
| return authorize(HiveOperation.SHOWDATABASES, LIST_DATABASES_PRIVILEGES, username, authorizable); |
| } |
| |
| /** |
| * Checks if a table is authorized to be accessed by the specific user. |
| * @return True if it is authorized, false otherwise. |
| */ |
| private boolean authorizeTable(String username, String dbName, String tableName) { |
| Database database = new Database(dbName); |
| Table table = new Table(tableName); |
| |
| List<DBModelAuthorizable> authorizable = Arrays.asList( |
| AUTH_SERVER, database, table, Column.ALL |
| ); |
| |
| return authorize(HiveOperation.SHOWTABLES, LIST_TABLES_PRIVILEGES, username, authorizable); |
| } |
| |
| /** |
| * Calls the authorization method of Sentry to check the access to a specific authorizable. |
| * @return True if it is authorized, false otherwise. |
| */ |
| private boolean authorize(HiveOperation op, HiveAuthzPrivileges privs, String username, List<DBModelAuthorizable> authorizable) { |
| try { |
| authzBinding.authorize(op, privs, new Subject(username), |
| Collections.singleton(authorizable), Collections.emptySet()); |
| } catch (AuthorizationException e) { |
| return false; |
| } |
| |
| return true; |
| } |
| } |