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.hdfs.DFSUtil;
033import org.apache.hadoop.security.AccessControlException;
034import org.apache.hadoop.security.UserGroupInformation;
035
036@InterfaceAudience.Public
037@InterfaceStability.Unstable
038public abstract class INodeAttributeProvider {
039
040  /**
041   * The AccessControlEnforcer allows implementations to override the
042   * default File System permission checking logic enforced on a file system
043   * object
044   */
045  public interface AccessControlEnforcer {
046
047    /**
048     * Checks permission on a file system object. Has to throw an Exception
049     * if the filesystem object is not accessessible by the calling Ugi.
050     * @param fsOwner Filesystem owner (The Namenode user)
051     * @param supergroup super user geoup
052     * @param callerUgi UserGroupInformation of the caller
053     * @param inodeAttrs Array of INode attributes for each path element in the
054     *                   the path
055     * @param inodes Array of INodes for each path element in the path
056     * @param pathByNameArr Array of byte arrays of the LocalName
057     * @param snapshotId the snapshotId of the requested path
058     * @param path Path String
059     * @param ancestorIndex Index of ancestor
060     * @param doCheckOwner perform ownership check
061     * @param ancestorAccess The access required by the ancestor of the path.
062     * @param parentAccess The access required by the parent of the path.
063     * @param access The access required by the path.
064     * @param subAccess If path is a directory, It is the access required of
065     *                  the path and all the sub-directories. If path is not a
066     *                  directory, there should ideally be no effect.
067     * @param ignoreEmptyDir Ignore permission checking for empty directory?
068     * @throws AccessControlException
069     */
070    public abstract void checkPermission(String fsOwner, String supergroup,
071        UserGroupInformation callerUgi, INodeAttributes[] inodeAttrs,
072        INode[] inodes, byte[][] pathByNameArr, int snapshotId, String path,
073        int ancestorIndex, boolean doCheckOwner, FsAction ancestorAccess,
074        FsAction parentAccess, FsAction access, FsAction subAccess,
075        boolean ignoreEmptyDir)
076            throws AccessControlException;
077
078  }
079  /**
080   * Initialize the provider. This method is called at NameNode startup
081   * time.
082   */
083  public abstract void start();
084
085  /**
086   * Shutdown the provider. This method is called at NameNode shutdown time.
087   */
088  public abstract void stop();
089
090  @VisibleForTesting
091  String[] getPathElements(String path) {
092    path = path.trim();
093    if (path.charAt(0) != Path.SEPARATOR_CHAR) {
094      throw new IllegalArgumentException("It must be an absolute path: " +
095          path);
096    }
097    int numOfElements = StringUtils.countMatches(path, Path.SEPARATOR);
098    if (path.length() > 1 && path.endsWith(Path.SEPARATOR)) {
099      numOfElements--;
100    }
101    String[] pathElements = new String[numOfElements];
102    int elementIdx = 0;
103    int idx = 0;
104    int found = path.indexOf(Path.SEPARATOR_CHAR, idx);
105    while (found > -1) {
106      if (found > idx) {
107        pathElements[elementIdx++] = path.substring(idx, found);
108      }
109      idx = found + 1;
110      found = path.indexOf(Path.SEPARATOR_CHAR, idx);
111    }
112    if (idx < path.length()) {
113      pathElements[elementIdx] = path.substring(idx);
114    }
115    return pathElements;
116  }
117
118  public INodeAttributes getAttributes(String fullPath, INodeAttributes inode) {
119    return getAttributes(getPathElements(fullPath), inode);
120  }
121
122  public abstract INodeAttributes getAttributes(String[] pathElements,
123      INodeAttributes inode);
124
125  public INodeAttributes getAttributes(byte[][] components,
126      INodeAttributes inode) {
127    String[] elements = new String[components.length];
128    for (int i = 0; i < elements.length; i++) {
129      elements[i] = DFSUtil.bytes2String(components[i]);
130    }
131    return getAttributes(elements, inode);
132  }
133
134  /**
135   * Can be over-ridden by implementations to provide a custom Access Control
136   * Enforcer that can provide an alternate implementation of the
137   * default permission checking logic.
138   * @param defaultEnforcer The Default AccessControlEnforcer
139   * @return The AccessControlEnforcer to use
140   */
141  public AccessControlEnforcer getExternalAccessControlEnforcer(
142      AccessControlEnforcer defaultEnforcer) {
143    return defaultEnforcer;
144  }
145}