// 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.impala.util;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.AclEntryType;
import org.apache.hadoop.fs.permission.AclStatus;
import org.apache.hadoop.fs.permission.AclEntryScope;
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.security.UserGroupInformation;
import org.apache.hadoop.hdfs.protocol.AclException;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_KEY;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;

/**
 * Singleton class that can check whether the current user has permission to access paths
 * in a FileSystem.
 */
public class FsPermissionChecker {
  private final static Logger LOG = LoggerFactory.getLogger(FsPermissionChecker.class);
  private final static FsPermissionChecker instance_;
  private final static Configuration CONF;
  protected final String user_;
  private final Set<String> groups_ = new HashSet<String>();
  private final String supergroup_;

  static {
    CONF = new Configuration();
    try {
      instance_ = new FsPermissionChecker();
    } catch (IOException e) {
      throw new RuntimeException(
          "Error initializing FsPermissionChecker: " + e.getMessage(), e);
    }
  }

  private FsPermissionChecker() throws IOException {
    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
    groups_.addAll(Arrays.asList(ugi.getGroupNames()));
    supergroup_ = CONF.get(DFS_PERMISSIONS_SUPERUSERGROUP_KEY,
        DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT);
    user_ = ugi.getShortUserName();
  }

  private boolean isSuperUser() { return groups_.contains(supergroup_); }

  private static List<AclEntryType> ACL_TYPE_PRIORITY =
      ImmutableList.of(AclEntryType.USER, AclEntryType.GROUP, AclEntryType.OTHER);

  /**
   * Allows checking different access permissions of a file without repeatedly accessing
   * the underlying filesystem by caching the results of a status call at construction.
   */
  public class Permissions {
    private final FileStatus fileStatus_;
    private final FsPermission permissions_;
    private final AclStatus aclStatus_;
    private Map<AclEntryType, List<AclEntry>> entriesByTypes_ = Maps.newHashMap();
    private AclEntry mask_;

    /**
     * If aclStatus is null, ACL permissions are not checked.
     */
    protected Permissions(FileStatus fileStatus, AclStatus aclStatus) {
      Preconditions.checkNotNull(fileStatus);
      fileStatus_ = fileStatus;
      permissions_ = fileStatus.getPermission();
      aclStatus_ = aclStatus;
      if (aclStatus_ == null) return;

      // Group the ACLs by type, so that we can apply them in correct priority order. Not
      // clear from documentation whether aclStatus_.getEntries() guarantees this
      // ordering, so this is defensive.
      for (AclEntryType t: ACL_TYPE_PRIORITY) {
        entriesByTypes_.put(t, Lists.<AclEntry>newArrayList());
      }

      List<AclEntry> fullAclList =
          getAclFromPermAndEntries(permissions_, aclStatus_.getEntries());
      for (AclEntry e: fullAclList) {
        if (e.getType() == AclEntryType.MASK && e.getScope() != AclEntryScope.DEFAULT) {
          mask_ = e;
        } else if (isApplicableAcl(e)) {
          entriesByTypes_.get(e.getType()).add(e);
        }
      }
    }

    /**
     * Returns true if the mask should apply. The mask ACL applies only to unnamed user
     * ACLs (e.g. user::r-x), and all group ACLs.
     */
    private boolean shouldApplyMask(AclEntry acl) {
      if (mask_ == null) return false;

      switch (acl.getType()) {
        case USER:
          return acl.getName() != null;
        case GROUP:
          return true;
      }
      return false;
    }

    /**
     * Returns true if this ACL applies to the current user and / or group
     */
    private boolean isApplicableAcl(AclEntry e) {
      // Default ACLs are not used for permission checking, but instead control the
      // permissions received by child directories
      if (e.getScope() == AclEntryScope.DEFAULT) return false;

      switch (e.getType()) {
        case USER:
          String aclUser = e.getName() == null ? aclStatus_.getOwner() : e.getName();
          return FsPermissionChecker.this.user_.equals(aclUser);
        case GROUP:
          String aclGroup = e.getName() == null ? aclStatus_.getGroup() : e.getName();
          return FsPermissionChecker.this.groups_.contains(aclGroup);
        case OTHER:
          return true;
        case MASK:
          return false;
        default:
          LOG.warn("Unknown Acl type: " + e.getType());
          return false;
      }
    }

    /**
     * Returns true if ACLs allow 'action', false if they explicitly disallow 'action',
     * and 'null' if no ACLs are available.
     * See http://users.suse.com/~agruen/acl/linux-acls/online for more details about
     * acl access check algorithm.
     */
    private Boolean checkAcls(FsAction action) {
      // ACLs may not be enabled, so we need this ternary logic. If no ACLs are available,
      // returning null causes us to fall back to standard ugo permissions.
      if (aclStatus_ == null) return null;

      // Remember if there is an applicable ACL entry, including owner user, named user,
      // owning group, named group.
      boolean foundMatch = false;
      for (AclEntryType t: ACL_TYPE_PRIORITY) {
        for (AclEntry e: entriesByTypes_.get(t)) {
          if (t == AclEntryType.OTHER) {
            // Processed all ACL entries except the OTHER entry.
            // If found applicable ACL entries but none of them contain requested
            // permission, deny access. Otherwise check OTHER entry.
            return foundMatch ? false : e.getPermission().implies(action);
          }
          // If there is an applicable mask, 'action' is allowed iff both the mask and
          // the underlying ACL permit it.
          if (e.getPermission().implies(action)) {
            if (shouldApplyMask(e)) {
              if (mask_.getPermission().implies(action)) return true;
            } else {
              return true;
            }
          }
          // User ACL entry has priority, no need to continue check.
          if (t == AclEntryType.USER) return false;

          foundMatch = true;
        }
      }
      return false;
    }

    /**
     * Returns true if the current user can perform the given action given these
     * permissions.
     */
    public boolean checkPermissions(FsAction action) {
      if (FsPermissionChecker.this.isSuperUser()) return true;
      Boolean aclPerms = checkAcls(action);
      if (aclPerms != null) return aclPerms;

      // Check user, group and then 'other' permissions in turn.
      if (FsPermissionChecker.this.user_.equals(fileStatus_.getOwner())) {
        // If the user matches, we must return their access rights whether or not the user
        // is allowed to access without checking the group. This is counter-intuitive if
        // the user cannot access the file, but the group permissions would allow it, but
        // is consistent with UNIX behaviour.
        return permissions_.getUserAction().implies(action);
      }

      if (FsPermissionChecker.this.groups_.contains(fileStatus_.getGroup())) {
        return permissions_.getGroupAction().implies(action);
      }
      return permissions_.getOtherAction().implies(action);
    }

    public boolean canRead() { return checkPermissions(FsAction.READ); }
    public boolean canWrite() { return checkPermissions(FsAction.WRITE); }
    public boolean canReadAndWrite() { return canRead() && canWrite(); }

    // This was originally lifted from Hadoop. Won't need it if HDFS-7177 is resolved.
    // getAclStatus() returns just extended ACL entries, the default file permissions
    // like "user::,group::,other::" are not included. We need to combine them together
    // to get full logic ACL list.
    private List<AclEntry> getAclFromPermAndEntries(FsPermission perm,
        List<AclEntry> entries) {
      // File permission always have 3 items.
      List<AclEntry> aclEntries = Lists.newArrayListWithCapacity(entries.size() + 3);

      // Owner entry implied by owner permission bits.
      aclEntries.add(new AclEntry.Builder()
          .setScope(AclEntryScope.ACCESS)
          .setType(AclEntryType.USER)
          .setPermission(perm.getUserAction())
          .build());

      // All extended access ACL entries add by "-setfacl" other than default file
      // permission.
      boolean hasAccessAcl = false;
      for (AclEntry entry: entries) {
        // AclEntry list should be ordered, all ACCESS one are in first half, DEFAULT one
        // are in second half, so no need to continue here.
        if (entry.getScope() == AclEntryScope.DEFAULT) break;
        hasAccessAcl = true;
        aclEntries.add(entry);
      }

      // Mask entry implied by group permission bits, or group entry if there is
      // no access ACL (only default ACL).
      aclEntries.add(new AclEntry.Builder()
          .setScope(AclEntryScope.ACCESS)
          .setType(hasAccessAcl ? AclEntryType.MASK : AclEntryType.GROUP)
          .setPermission(perm.getGroupAction())
          .build());

      // Other entry implied by other bits.
      aclEntries.add(new AclEntry.Builder()
          .setScope(AclEntryScope.ACCESS)
          .setType(AclEntryType.OTHER)
          .setPermission(perm.getOtherAction())
          .build());

      return aclEntries;
    }
  }

  /**
   * Returns a Permissions object that can answer all access permission queries for the
   * given path.
   */
  public Permissions getPermissions(FileSystem fs, Path path) throws IOException {
    Preconditions.checkNotNull(fs);
    Preconditions.checkNotNull(path);
    return getPermissions(fs, fs.getFileStatus(path));
  }

  /**
   * Returns a Permissions object for the given FileStatus object. In the common
   * case that ACLs are not in use, this does not require any additional round-trip
   * to the FileSystem. This allows batch construction using APIs like
   * FileSystem.listStatus(...).
   */
  public Permissions getPermissions(FileSystem fs, FileStatus fileStatus)
      throws IOException {
    AclStatus aclStatus = null;
    if (fileStatus.getPermission().getAclBit()) {
      try {
        aclStatus = fs.getAclStatus(fileStatus.getPath());
      } catch (AclException ex) {
        if (LOG.isTraceEnabled()) {
          LOG.trace(
              "No ACLs retrieved, skipping ACLs check (HDFS will enforce ACLs)", ex);
        }
      } catch (UnsupportedOperationException ex) {
        if (LOG.isTraceEnabled()) LOG.trace("No ACLs retrieved, unsupported", ex);
      }
    }
    return new Permissions(fileStatus, aclStatus);
  }

  /**
   * Returns the FsPermissionChecker singleton.
   */
  public static FsPermissionChecker getInstance() { return instance_; }
}
