001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hdfs.server.namenode;
019
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.HashSet;
023import java.util.Set;
024
025import com.google.common.annotations.VisibleForTesting;
026
027import org.apache.commons.lang.StringUtils;
028import org.apache.hadoop.classification.InterfaceAudience;
029import org.apache.hadoop.classification.InterfaceStability;
030import org.apache.hadoop.fs.Path;
031import org.apache.hadoop.fs.permission.FsAction;
032import org.apache.hadoop.security.AccessControlException;
033import org.apache.hadoop.security.UserGroupInformation;
034
035@InterfaceAudience.Public
036@InterfaceStability.Unstable
037public abstract class INodeAttributeProvider {
038
039  /**
040   * The AccessControlEnforcer allows implementations to override the
041   * default File System permission checking logic enforced on a file system
042   * object
043   */
044  public interface AccessControlEnforcer {
045
046    /**
047     * Checks permission on a file system object. Has to throw an Exception
048     * if the filesystem object is not accessessible by the calling Ugi.
049     * @param fsOwner Filesystem owner (The Namenode user)
050     * @param supergroup super user geoup
051     * @param callerUgi UserGroupInformation of the caller
052     * @param inodeAttrs Array of INode attributes for each path element in the
053     *                   the path
054     * @param inodes Array of INodes for each path element in the path
055     * @param pathByNameArr Array of byte arrays of the LocalName
056     * @param snapshotId the snapshotId of the requested path
057     * @param path Path String
058     * @param ancestorIndex Index of ancestor
059     * @param doCheckOwner perform ownership check
060     * @param ancestorAccess The access required by the ancestor of the path.
061     * @param parentAccess The access required by the parent of the path.
062     * @param access The access required by the path.
063     * @param subAccess If path is a directory, It is the access required of
064     *                  the path and all the sub-directories. If path is not a
065     *                  directory, there should ideally be no effect.
066     * @param ignoreEmptyDir Ignore permission checking for empty directory?
067     * @throws AccessControlException
068     */
069    public abstract void checkPermission(String fsOwner, String supergroup,
070        UserGroupInformation callerUgi, INodeAttributes[] inodeAttrs,
071        INode[] inodes, byte[][] pathByNameArr, int snapshotId, String path,
072        int ancestorIndex, boolean doCheckOwner, FsAction ancestorAccess,
073        FsAction parentAccess, FsAction access, FsAction subAccess,
074        boolean ignoreEmptyDir)
075            throws AccessControlException;
076
077  }
078  /**
079   * Initialize the provider. This method is called at NameNode startup
080   * time.
081   */
082  public abstract void start();
083
084  /**
085   * Shutdown the provider. This method is called at NameNode shutdown time.
086   */
087  public abstract void stop();
088
089  @VisibleForTesting
090  String[] getPathElements(String path) {
091    path = path.trim();
092    if (path.charAt(0) != Path.SEPARATOR_CHAR) {
093      throw new IllegalArgumentException("It must be an absolute path: " +
094          path);
095    }
096    int numOfElements = StringUtils.countMatches(path, Path.SEPARATOR);
097    if (path.length() > 1 && path.endsWith(Path.SEPARATOR)) {
098      numOfElements--;
099    }
100    String[] pathElements = new String[numOfElements];
101    int elementIdx = 0;
102    int idx = 0;
103    int found = path.indexOf(Path.SEPARATOR_CHAR, idx);
104    while (found > -1) {
105      if (found > idx) {
106        pathElements[elementIdx++] = path.substring(idx, found);
107      }
108      idx = found + 1;
109      found = path.indexOf(Path.SEPARATOR_CHAR, idx);
110    }
111    if (idx < path.length()) {
112      pathElements[elementIdx] = path.substring(idx);
113    }
114    return pathElements;
115  }
116
117  public INodeAttributes getAttributes(String fullPath, INodeAttributes inode) {
118    return getAttributes(getPathElements(fullPath), inode);
119  }
120
121  public abstract INodeAttributes getAttributes(String[] pathElements,
122      INodeAttributes inode);
123
124  /**
125   * Can be over-ridden by implementations to provide a custom Access Control
126   * Enforcer that can provide an alternate implementation of the
127   * default permission checking logic.
128   * @param defaultEnforcer The Default AccessControlEnforcer
129   * @return The AccessControlEnforcer to use
130   */
131  public AccessControlEnforcer getExternalAccessControlEnforcer(
132      AccessControlEnforcer defaultEnforcer) {
133    return defaultEnforcer;
134  }
135}