Package org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd

Source Code of org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLAuthorizationUtils

/**
* 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.sqlstd;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.hadoop.hive.common.FileUtils;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.IMetaStoreClient;
import org.apache.hadoop.hive.metastore.MetaStoreUtils;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.HiveObjectPrivilege;
import org.apache.hadoop.hive.metastore.api.HiveObjectRef;
import org.apache.hadoop.hive.metastore.api.HiveObjectType;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.hive.metastore.api.PrincipalPrivilegeSet;
import org.apache.hadoop.hive.metastore.api.PrincipalType;
import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
import org.apache.hadoop.hive.metastore.api.PrivilegeGrantInfo;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.security.authorization.AuthorizationUtils;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrincipal;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilege;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType;
import org.apache.thrift.TException;

public class SQLAuthorizationUtils {

  private static final String[] SUPPORTED_PRIVS = { "INSERT", "UPDATE", "DELETE", "SELECT" };
  private static final Set<String> SUPPORTED_PRIVS_SET = new HashSet<String>(
      Arrays.asList(SUPPORTED_PRIVS));
  public static final Log LOG = LogFactory.getLog(SQLAuthorizationUtils.class);

  /**
   * Create thrift privileges bag
   *
   * @param hivePrincipals
   * @param hivePrivileges
   * @param hivePrivObject
   * @param grantorPrincipal
   * @param grantOption
   * @return
   * @throws HiveAuthzPluginException
   */
  static PrivilegeBag getThriftPrivilegesBag(List<HivePrincipal> hivePrincipals,
      List<HivePrivilege> hivePrivileges, HivePrivilegeObject hivePrivObject,
      HivePrincipal grantorPrincipal, boolean grantOption) throws HiveAuthzPluginException {
    HiveObjectRef privObj = getThriftHiveObjectRef(hivePrivObject);
    PrivilegeBag privBag = new PrivilegeBag();
    for (HivePrivilege privilege : hivePrivileges) {
      if (privilege.getColumns() != null && privilege.getColumns().size() > 0) {
        throw new HiveAuthzPluginException("Privileges on columns not supported currently"
            + " in sql standard authorization mode");
      }
      if (!SUPPORTED_PRIVS_SET.contains(privilege.getName().toUpperCase(Locale.US))) {
        throw new HiveAuthzPluginException("Privilege: " + privilege.getName()
            + " is not supported in sql standard authorization mode");
      }
      PrivilegeGrantInfo grantInfo = getThriftPrivilegeGrantInfo(privilege, grantorPrincipal,
          grantOption, 0 /*real grant time added by metastore*/);
      for (HivePrincipal principal : hivePrincipals) {
        HiveObjectPrivilege objPriv = new HiveObjectPrivilege(privObj, principal.getName(),
            AuthorizationUtils.getThriftPrincipalType(principal.getType()), grantInfo);
        privBag.addToPrivileges(objPriv);
      }
    }
    return privBag;
  }

  static PrivilegeGrantInfo getThriftPrivilegeGrantInfo(HivePrivilege privilege,
      HivePrincipal grantorPrincipal, boolean grantOption, int grantTime)
          throws HiveAuthzPluginException {
    try {
      return AuthorizationUtils.getThriftPrivilegeGrantInfo(privilege, grantorPrincipal,
          grantOption, grantTime);
    } catch (HiveException e) {
      throw new HiveAuthzPluginException(e);
    }
  }

  /**
   * Create a thrift privilege object from the plugin interface privilege object
   *
   * @param privObj
   * @return
   * @throws HiveAuthzPluginException
   */
  static HiveObjectRef getThriftHiveObjectRef(HivePrivilegeObject privObj)
      throws HiveAuthzPluginException {
    try {
      return AuthorizationUtils.getThriftHiveObjectRef(privObj);
    } catch (HiveException e) {
      throw new HiveAuthzPluginException(e);
    }
  }

  static HivePrivilegeObjectType getPluginObjType(HiveObjectType objectType)
      throws HiveAuthzPluginException {
    switch (objectType) {
    case DATABASE:
      return HivePrivilegeObjectType.DATABASE;
    case TABLE:
      return HivePrivilegeObjectType.TABLE_OR_VIEW;
    case COLUMN:
    case GLOBAL:
    case PARTITION:
      throw new HiveAuthzPluginException("Unsupported object type " + objectType);
    default:
      throw new AssertionError("Unexpected object type " + objectType);
    }
  }

  /**
   * Check if the privileges are acceptable for SQL Standard authorization implementation
   * @param hivePrivileges
   * @throws HiveAuthzPluginException
   */
  public static void validatePrivileges(List<HivePrivilege> hivePrivileges) throws HiveAuthzPluginException {
    for (HivePrivilege hivePrivilege : hivePrivileges) {
      if (hivePrivilege.getColumns() != null && hivePrivilege.getColumns().size() != 0) {
        throw new HiveAuthzPluginException(
            "Privilege with columns are not currently supported with sql standard authorization:"
                + hivePrivilege);
      }
      //try converting to the enum to verify that this is a valid privilege type
      SQLPrivilegeType.getRequirePrivilege(hivePrivilege.getName());

    }
  }

  /**
   * Get the privileges this user(userName argument) has on the object
   * (hivePrivObject argument) If isAdmin is true, adds an admin privilege as
   * well.
   *
   * @param metastoreClient
   * @param userName
   * @param hivePrivObject
   * @param curRoles
   *          current active roles for user
   * @param isAdmin
   *          if user can run as admin user
   * @return
   * @throws HiveAuthzPluginException
   */
  static RequiredPrivileges getPrivilegesFromMetaStore(IMetaStoreClient metastoreClient,
      String userName, HivePrivilegeObject hivePrivObject, List<String> curRoles, boolean isAdmin)
          throws HiveAuthzPluginException {

    // get privileges for this user and its role on this object
    PrincipalPrivilegeSet thrifPrivs = null;
    try {
      thrifPrivs = metastoreClient.get_privilege_set(
          AuthorizationUtils.getThriftHiveObjectRef(hivePrivObject), userName, null);
    } catch (MetaException e) {
      throwGetPrivErr(e, hivePrivObject, userName);
    } catch (TException e) {
      throwGetPrivErr(e, hivePrivObject, userName);
    } catch (HiveException e) {
      throwGetPrivErr(e, hivePrivObject, userName);
    }

    filterPrivsByCurrentRoles(thrifPrivs, curRoles);

    // convert to RequiredPrivileges
    RequiredPrivileges privs = getRequiredPrivsFromThrift(thrifPrivs);

    // add owner privilege if user is owner of the object
    if (isOwner(metastoreClient, userName, curRoles, hivePrivObject)) {
      privs.addPrivilege(SQLPrivTypeGrant.OWNER_PRIV);
    }
    if (isAdmin) {
      privs.addPrivilege(SQLPrivTypeGrant.ADMIN_PRIV);
    }

    return privs;
  }

  /**
   * Remove any role privileges that don't belong to the roles in curRoles
   * @param thriftPrivs
   * @param curRoles
   * @return
   */
  private static void filterPrivsByCurrentRoles(PrincipalPrivilegeSet thriftPrivs,
      List<String> curRoles) {
    // check if there are privileges to be filtered
    if(thriftPrivs == null || thriftPrivs.getRolePrivileges() == null
        || thriftPrivs.getRolePrivilegesSize() == 0
        ){
      // no privileges to filter
      return;
    }

    // add the privs for roles in curRoles to new role-to-priv map
    Map<String, List<PrivilegeGrantInfo>> filteredRolePrivs = new HashMap<String, List<PrivilegeGrantInfo>>();
    for(String role : curRoles){
      List<PrivilegeGrantInfo> privs = thriftPrivs.getRolePrivileges().get(role);
      if(privs != null){
        filteredRolePrivs.put(role, privs);
      }
    }
    thriftPrivs.setRolePrivileges(filteredRolePrivs);
  }

  /**
   * Check if user is owner of the given object
   *
   * @param metastoreClient
   * @param userName
   *          current user
   * @param curRoles
   *          current roles for userName
   * @param hivePrivObject
   *          given object
   * @return true if user is owner
   * @throws HiveAuthzPluginException
   */
  private static boolean isOwner(IMetaStoreClient metastoreClient, String userName,
      List<String> curRoles, HivePrivilegeObject hivePrivObject) throws HiveAuthzPluginException {
    // for now, check only table & db
    switch (hivePrivObject.getType()) {
    case TABLE_OR_VIEW: {
      Table thriftTableObj = null;
      try {
        thriftTableObj = metastoreClient.getTable(hivePrivObject.getDbname(),
            hivePrivObject.getTableViewURI());
      } catch (Exception e) {
        throwGetObjErr(e, hivePrivObject);
      }
      return userName.equals(thriftTableObj.getOwner());
    }
    case DATABASE: {
      if (MetaStoreUtils.DEFAULT_DATABASE_NAME.equalsIgnoreCase(hivePrivObject.getDbname())) {
        return true;
      }
      Database db = null;
      try {
        db = metastoreClient.getDatabase(hivePrivObject.getDbname());
      } catch (Exception e) {
        throwGetObjErr(e, hivePrivObject);
      }
      // a db owner can be a user or a role
      if(db.getOwnerType() == PrincipalType.USER){
        return userName.equals(db.getOwnerName());
      } else if(db.getOwnerType() == PrincipalType.ROLE){
        // check if any of the roles of this user is an owner
        return curRoles.contains(db.getOwnerName());
      } else {
        // looks like owner is an unsupported type
        LOG.warn("Owner of database " + db.getName() + " is of unsupported type "
            + db.getOwnerType());
        return false;
      }
    }
    case DFS_URI:
    case LOCAL_URI:
    case PARTITION:
    default:
      return false;
    }
  }

  private static void throwGetObjErr(Exception e, HivePrivilegeObject hivePrivObject)
      throws HiveAuthzPluginException {
    String msg = "Error getting object from metastore for " + hivePrivObject;
    throw new HiveAuthzPluginException(msg, e);
  }

  private static void throwGetPrivErr(Exception e, HivePrivilegeObject hivePrivObject,
      String userName) throws HiveAuthzPluginException {
    String msg = "Error getting privileges on " + hivePrivObject + " for " + userName + ": "
      + e.getMessage();
    throw new HiveAuthzPluginException(msg, e);
  }

  private static RequiredPrivileges getRequiredPrivsFromThrift(PrincipalPrivilegeSet thrifPrivs)
      throws HiveAuthzPluginException {

    RequiredPrivileges reqPrivs = new RequiredPrivileges();
    // add user privileges
    Map<String, List<PrivilegeGrantInfo>> userPrivs = thrifPrivs.getUserPrivileges();
    if (userPrivs != null && userPrivs.size() != 1) {
      throw new HiveAuthzPluginException("Invalid number of user privilege objects: "
          + userPrivs.size());
    }
    addRequiredPrivs(reqPrivs, userPrivs);

    // add role privileges
    Map<String, List<PrivilegeGrantInfo>> rolePrivs = thrifPrivs.getRolePrivileges();
    addRequiredPrivs(reqPrivs, rolePrivs);
    return reqPrivs;
  }

  /**
   * Add privileges to RequiredPrivileges object reqPrivs from thrift availPrivs
   * object
   * @param reqPrivs
   * @param availPrivs
   * @throws HiveAuthzPluginException
   */
  private static void addRequiredPrivs(RequiredPrivileges reqPrivs,
      Map<String, List<PrivilegeGrantInfo>> availPrivs) throws HiveAuthzPluginException {
    if(availPrivs == null){
      return;
    }
    for (Map.Entry<String, List<PrivilegeGrantInfo>> userPriv : availPrivs.entrySet()) {
      List<PrivilegeGrantInfo> userPrivGInfos = userPriv.getValue();
      for (PrivilegeGrantInfo userPrivGInfo : userPrivGInfos) {
        reqPrivs.addPrivilege(userPrivGInfo.getPrivilege(), userPrivGInfo.isGrantOption());
      }
    }
  }

  public static void assertNoMissingPrivilege(Collection<SQLPrivTypeGrant> missingPrivs,
      HivePrincipal hivePrincipal, HivePrivilegeObject hivePrivObject)
      throws HiveAccessControlException {
    if (missingPrivs.size() != 0) {
      // there are some required privileges missing, create error message
      // sort the privileges so that error message is deterministic (for tests)
      List<SQLPrivTypeGrant> sortedmissingPrivs = new ArrayList<SQLPrivTypeGrant>(missingPrivs);
      Collections.sort(sortedmissingPrivs);

      String errMsg = "Permission denied. " + hivePrincipal
          + " does not have following privileges on " + hivePrivObject + " : " + sortedmissingPrivs;
      throw new HiveAccessControlException(errMsg.toString());
    }
  }

  /**
   * Map permissions for this uri to SQL Standard privileges
   * @param filePath
   * @param conf
   * @param userName
   * @return
   * @throws HiveAuthzPluginException
   */
  public static RequiredPrivileges getPrivilegesFromFS(Path filePath, HiveConf conf,
      String userName) throws HiveAuthzPluginException {
    // get the 'available privileges' from file system


    RequiredPrivileges availPrivs = new RequiredPrivileges();
    // check file system permission
    FileSystem fs;
    try {
      fs = FileSystem.get(filePath.toUri(), conf);
      Path path = FileUtils.getPathOrParentThatExists(fs, filePath);
      FileStatus fileStatus = fs.getFileStatus(path);
      if (FileUtils.isOwnerOfFileHierarchy(fs, fileStatus, userName)) {
        availPrivs.addPrivilege(SQLPrivTypeGrant.OWNER_PRIV);
      }
      if (FileUtils.isActionPermittedForFileHierarchy(fs, fileStatus, userName, FsAction.WRITE)) {
        availPrivs.addPrivilege(SQLPrivTypeGrant.INSERT_NOGRANT);
        availPrivs.addPrivilege(SQLPrivTypeGrant.DELETE_NOGRANT);
      }
      if (FileUtils.isActionPermittedForFileHierarchy(fs, fileStatus, userName, FsAction.READ)) {
        availPrivs.addPrivilege(SQLPrivTypeGrant.SELECT_NOGRANT);
      }
    } catch (IOException e) {
      String msg = "Error getting permissions for " + filePath + ": " + e.getMessage();
      throw new HiveAuthzPluginException(msg, e);
    }
    return availPrivs;
  }


}
TOP

Related Classes of org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLAuthorizationUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.