Package org.apache.hcatalog.security

Source Code of org.apache.hcatalog.security.HdfsAuthorizationProvider

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

import static org.apache.hadoop.hive.metastore.MetaStoreUtils.DEFAULT_DATABASE_NAME;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;

import javax.security.auth.login.LoginException;

import org.apache.commons.lang.ArrayUtils;
import org.apache.hadoop.conf.Configuration;
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.fs.permission.FsPermission;
import org.apache.hadoop.hive.metastore.Warehouse;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.hive.ql.metadata.AuthorizationException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.metadata.Partition;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.security.authorization.HiveAuthorizationProviderBase;
import org.apache.hadoop.hive.ql.security.authorization.Privilege;
import org.apache.hadoop.hive.shims.HadoopShims;
import org.apache.hadoop.hive.shims.ShimLoader;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;

/**
* An AuthorizationProvider, which checks against the data access level permissions on HDFS.
*/
public class HdfsAuthorizationProvider extends HiveAuthorizationProviderBase {

  protected Warehouse wh;
 
  public HdfsAuthorizationProvider() {
    super();
  }
 
  public HdfsAuthorizationProvider(Configuration conf) {
    super();
    setConf(conf);
  }
 
  @Override
  public void setConf(Configuration conf) {
    super.setConf(conf);
    try {
      this.wh = new Warehouse(conf);
    } catch (MetaException ex) {
      throw new RuntimeException(ex);
    }
  }
 
  protected FsAction getFsAction(Privilege priv, Path path) {
   
    switch (priv.getPriv()) {
    case ALL            : throw new AuthorizationException("no matching Action for Privilege.All");
    case ALTER_DATA     : return FsAction.WRITE;  
    case ALTER_METADATA : return FsAction.WRITE; 
    case CREATE         : return FsAction.WRITE;
    case DROP           : return FsAction.WRITE;
    case INDEX          : return FsAction.WRITE;
    case LOCK           : return FsAction.WRITE;
    case SELECT         : return FsAction.READ;
    case SHOW_DATABASE  : return FsAction.READ;
    case UNKNOWN        :
    default             : throw new AuthorizationException("Unknown privilege");
    }
  }
 
  protected EnumSet<FsAction> getFsActions(Privilege[] privs, Path path) {
    EnumSet<FsAction> actions = EnumSet.noneOf(FsAction.class);
   
    if (privs == null) {
      return actions;
    }
   
    for (Privilege priv : privs) {
      actions.add(getFsAction(priv, path));
    }
   
    return actions;
  }
 
  private static final String DATABASE_WAREHOUSE_SUFFIX = ".db";

  private Path getDefaultDatabasePath(String dbName) throws MetaException {
    if (dbName.equalsIgnoreCase(DEFAULT_DATABASE_NAME)) {
      return wh.getWhRoot();
    }
    return new Path(wh.getWhRoot(), dbName.toLowerCase() + DATABASE_WAREHOUSE_SUFFIX);
  }
 
  protected Path getDbLocation(Database db) throws HiveException {
    try {
      String location = db.getLocationUri();
      if (location == null) {
        return getDefaultDatabasePath(db.getName());
      } else {
        return wh.getDnsPath(wh.getDatabasePath(db));
      }
    } catch (MetaException ex) {
      throw new HiveException(ex.getMessage());
    }
  }
 
  @Override
  public void authorize(Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
    //Authorize for global level permissions at the warehouse dir
    Path root;
    try {
      root = wh.getWhRoot();
      authorize(root, readRequiredPriv, writeRequiredPriv);
    } catch (MetaException ex) {
      throw new HiveException(ex);
    }
  }

  @Override
  public void authorize(Database db, Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
    if (db == null) {
      return;
    }

    Path path = getDbLocation(db);
   
    authorize(path, readRequiredPriv, writeRequiredPriv);
  }

  @Override
  public void authorize(Table table, Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
    if (table == null) {
      return;
    }
   
    //unlike Hive's model, this can be called at CREATE TABLE as well, since we should authorize
    //against the table's declared location
    Path path = null;
    try {
      if (table.getTTable().getSd().getLocation() == null
          || table.getTTable().getSd().getLocation().isEmpty()) {
            path = wh.getTablePath(hive_db.getDatabase(table.getDbName()), table.getTableName());
      } else {
         path = table.getPath();
      }
    } catch (MetaException ex) {
      throw new HiveException(ex);
    }
   
    authorize(path, readRequiredPriv, writeRequiredPriv);
  }

  //TODO: HiveAuthorizationProvider should expose this interface instead of #authorize(Partition, Privilege[], Privilege[])
  public void authorize(Table table, Partition part, Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
   
    if (part == null || part.getLocation() == null) {
      authorize(table, readRequiredPriv, writeRequiredPriv);
    } else {
      authorize(part.getPartitionPath(), readRequiredPriv, writeRequiredPriv);
    }
  }

  @Override
  public void authorize(Partition part, Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
    if (part == null) {
      return;
    }
    authorize(part.getTable(), part, readRequiredPriv, writeRequiredPriv);
  }

  @Override
  public void authorize(Table table, Partition part, List<String> columns,
      Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv) throws HiveException,
      AuthorizationException {
    //columns cannot live in different files, just check for partition level permissions
    authorize(table, part, readRequiredPriv, writeRequiredPriv);
  }
 
  /**
   * Authorization privileges against a path.
   * @param path a filesystem path
   * @param readRequiredPriv a list of privileges needed for inputs.
   * @param writeRequiredPriv a list of privileges needed for outputs.
   */
  public void authorize(Path path, Privilege[] readRequiredPriv, Privilege[] writeRequiredPriv)
      throws HiveException, AuthorizationException {
    try {
      EnumSet<FsAction> actions = getFsActions(readRequiredPriv, path);
      actions.addAll(getFsActions(writeRequiredPriv, path));
      if (actions.isEmpty()) {
        return;
      }
     
      checkPermissions(getConf(), path, actions);
     
    } catch (AccessControlException ex) {
      throw new AuthorizationException(ex);
    } catch (LoginException ex) {
      throw new AuthorizationException(ex);
    } catch (IOException ex) {
      throw new HiveException(ex);
    }
  }
 
  /**
   * Checks the permissions for the given path and current user on Hadoop FS. If the given path
   * does not exists, it checks for it's parent folder.
   */
  public static void checkPermissions(final Configuration conf, final Path path,
      final EnumSet<FsAction> actions) throws IOException, LoginException {

    if (path == null) {
      throw new IllegalArgumentException("path is null");
    }
   
    final UserGroupInformation ugi;
   
    HadoopShims shims = ShimLoader.getHadoopShims();
    ugi = shims.getUGIForConf(conf);
    final String user = shims.getShortUserName(ugi)
       
    final FileSystem fs = path.getFileSystem(conf);

    if (fs.exists(path)) {
      checkPermissions(fs, path, actions, user, ugi.getGroupNames());
    } else if (path.getParent() != null) {
      // find the ancestor which exists to check it's permissions
      Path par = path.getParent();
      while (par != null) {
        if (fs.exists(par)) {
          break;
        }
        par = par.getParent();
      }

      checkPermissions(fs, par, actions, user, ugi.getGroupNames());
    }
  }
 
  /**
   * Checks the permissions for the given path and current user on Hadoop FS. If the given path
   * does not exists, it returns.
   */
  @SuppressWarnings("deprecation")
  public static void checkPermissions(final FileSystem fs, final Path path,
      final EnumSet<FsAction> actions, String user, String[] groups) throws IOException,
      AccessControlException {
   
    final FileStatus stat;

    try {
      stat = fs.getFileStatus(path);
    } catch (FileNotFoundException fnfe) {
      // File named by path doesn't exist; nothing to validate.
      return;
    } catch (org.apache.hadoop.fs.permission.AccessControlException ace) {
      // Older hadoop version will throw this @deprecated Exception.
      throw new AccessControlException(ace.getMessage());
    }

    final FsPermission dirPerms = stat.getPermission();
    final String grp = stat.getGroup();

    for (FsAction action : actions) {
      if (user.equals(stat.getOwner())) {
        if (dirPerms.getUserAction().implies(action)) {
          continue;
        }
      }
      if (ArrayUtils.contains(groups, grp)) {
        if (dirPerms.getGroupAction().implies(action)) {
          continue;
        }
      }
      if (dirPerms.getOtherAction().implies(action)) {
        continue;
      }
      throw new AccessControlException("action " + action + " not permitted on path "
          + path + " for user " + user);
    }
  }
}
TOP

Related Classes of org.apache.hcatalog.security.HdfsAuthorizationProvider

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.