TestDFSPermission.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:35k
源码类别:

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.hdfs;
  19. import java.io.IOException;
  20. import java.util.Random;
  21. import javax.security.auth.login.LoginException;
  22. import org.apache.commons.logging.*;
  23. import org.apache.hadoop.conf.Configuration;
  24. import org.apache.hadoop.hdfs.MiniDFSCluster;
  25. import org.apache.hadoop.hdfs.server.common.Util;
  26. import org.apache.hadoop.fs.*;
  27. import org.apache.hadoop.fs.permission.*;
  28. import org.apache.hadoop.security.AccessControlException;
  29. import org.apache.hadoop.security.UnixUserGroupInformation;
  30. import junit.framework.AssertionFailedError;
  31. import junit.framework.TestCase;
  32. /** Unit tests for permission */
  33. public class TestDFSPermission extends TestCase {
  34.   public static final Log LOG = LogFactory.getLog(TestDFSPermission.class);
  35.   final private static Configuration conf = new Configuration();
  36.   
  37.   final private static String GROUP1_NAME = "group1";
  38.   final private static String GROUP2_NAME = "group2";
  39.   final private static String GROUP3_NAME = "group3";
  40.   final private static String GROUP4_NAME = "group4";
  41.   final private static String USER1_NAME = "user1";
  42.   final private static String USER2_NAME = "user2";
  43.   final private static String USER3_NAME = "user3";
  44.   private static UnixUserGroupInformation SUPERUSER;
  45.   private static UnixUserGroupInformation USER1;
  46.   private static UnixUserGroupInformation USER2;
  47.   private static UnixUserGroupInformation USER3;
  48.   
  49.   final private static short MAX_PERMISSION = 511;
  50.   final private static short DEFAULT_UMASK = 022;
  51.   final private static short FILE_MASK = 0666;
  52.   final private static FsPermission DEFAULT_PERMISSION = 
  53.     FsPermission.createImmutable((short) 0777);
  54.   final static private int NUM_TEST_PERMISSIONS = 
  55.     conf.getInt("test.dfs.permission.num", 10) * (MAX_PERMISSION + 1) / 100;
  56.   final private static String PATH_NAME = "xx";
  57.   final private static Path FILE_DIR_PATH = new Path("/", PATH_NAME);
  58.   final private static Path NON_EXISTENT_PATH = new Path("/parent", PATH_NAME);
  59.   final private static Path NON_EXISTENT_FILE = new Path("/NonExistentFile");
  60.   private FileSystem fs;
  61.   private static Random r;
  62.   static {
  63.     try {
  64.       // Initiate the random number generator and logging the seed
  65.       long seed = Util.now();
  66.       r = new Random(seed);
  67.       LOG.info("Random number generator uses seed " + seed);
  68.       LOG.info("NUM_TEST_PERMISSIONS=" + NUM_TEST_PERMISSIONS);
  69.       
  70.       // explicitly turn on permission checking
  71.       conf.setBoolean("dfs.permissions", true);
  72.       
  73.       // Initiate all four users
  74.       SUPERUSER = UnixUserGroupInformation.login(conf);
  75.       USER1 = new UnixUserGroupInformation(USER1_NAME, new String[] {
  76.           GROUP1_NAME, GROUP2_NAME });
  77.       USER2 = new UnixUserGroupInformation(USER2_NAME, new String[] {
  78.           GROUP2_NAME, GROUP3_NAME });
  79.       USER3 = new UnixUserGroupInformation(USER3_NAME, new String[] {
  80.           GROUP3_NAME, GROUP4_NAME });
  81.     } catch (LoginException e) {
  82.       throw new RuntimeException(e);
  83.     }
  84.   }
  85.   /** This tests if permission setting in create, mkdir, and 
  86.    * setPermission works correctly
  87.    */
  88.   public void testPermissionSetting() throws Exception {
  89.     MiniDFSCluster cluster = new MiniDFSCluster(conf, 3, true, null);
  90.     try {
  91.       cluster.waitActive();
  92.       fs = FileSystem.get(conf);
  93.       LOG.info("ROOT=" + fs.getFileStatus(new Path("/")));
  94.       testPermissionSetting(OpType.CREATE); // test file creation
  95.       testPermissionSetting(OpType.MKDIRS); // test directory creation
  96.     } finally {
  97.       fs.close();
  98.       cluster.shutdown();
  99.     }
  100.   }
  101.   /* check permission setting works correctly for file or directory */
  102.   private void testPermissionSetting(OpType op) throws Exception {
  103.     // case 1: use default permission but all possible umasks
  104.     PermissionGenerator generator = new PermissionGenerator(r);
  105.     for (short i = 0; i < NUM_TEST_PERMISSIONS; i++) {
  106.       createAndCheckPermission(op, FILE_DIR_PATH, generator.next(),
  107.           new FsPermission(DEFAULT_PERMISSION), true);
  108.     }
  109.     // case 2: use permission 0643 and the default umask
  110.     createAndCheckPermission(op, FILE_DIR_PATH, DEFAULT_UMASK,
  111.         new FsPermission((short) 0643), true);
  112.     // case 3: use permission 0643 and umask 0222
  113.     createAndCheckPermission(op, FILE_DIR_PATH, (short) 0222, 
  114.         new FsPermission((short) 0643), false);
  115.     // case 4: set permission
  116.     fs.setPermission(FILE_DIR_PATH, new FsPermission((short) 0111));
  117.     short expectedPermission = (short) ((op == OpType.CREATE) ? 0 : 0111);
  118.     checkPermission(FILE_DIR_PATH, expectedPermission, true);
  119.     // case 5: test non-existent parent directory
  120.     assertFalse(fs.exists(NON_EXISTENT_PATH));
  121.     createAndCheckPermission(op, NON_EXISTENT_PATH, DEFAULT_UMASK,
  122.         new FsPermission(DEFAULT_PERMISSION), false);
  123.     Path parent = NON_EXISTENT_PATH.getParent();
  124.     checkPermission(parent, getPermission(parent.getParent()), true);
  125.   }
  126.   /* get the permission of a file/directory */
  127.   private short getPermission(Path path) throws IOException {
  128.     return fs.getFileStatus(path).getPermission().toShort();
  129.   }
  130.   /* create a file/directory with the default umask and permission */
  131.   private void create(OpType op, Path name) throws IOException {
  132.     create(op, name, DEFAULT_UMASK, new FsPermission(DEFAULT_PERMISSION));
  133.   }
  134.   /* create a file/directory with the given umask and permission */
  135.   private void create(OpType op, Path name, short umask, 
  136.       FsPermission permission) throws IOException {
  137.     // set umask in configuration
  138.     conf.setInt(FsPermission.UMASK_LABEL, umask);
  139.     // create the file/directory
  140.     switch (op) {
  141.     case CREATE:
  142.       FSDataOutputStream out = fs.create(name, permission, true, conf.getInt(
  143.           "io.file.buffer.size", 4096), fs.getDefaultReplication(), fs
  144.           .getDefaultBlockSize(), null);
  145.       out.close();
  146.       break;
  147.     case MKDIRS:
  148.       fs.mkdirs(name, permission);
  149.       break;
  150.     default:
  151.       throw new IOException("Unsupported operation: " + op);
  152.     }
  153.   }
  154.   /* create file/directory with the provided umask and permission; then it
  155.    * checks if the permission is set correctly;
  156.    * If the delete flag is true, delete the file afterwards; otherwise leave
  157.    * it in the file system.
  158.    */
  159.   private void createAndCheckPermission(OpType op, Path name, short umask,
  160.       FsPermission permission, boolean delete) throws Exception {
  161.     // create the file/directory
  162.     create(op, name, umask, permission);
  163.     // get the short form of the permission
  164.     short permissionNum = (DEFAULT_PERMISSION.equals(permission)) ? MAX_PERMISSION
  165.         : permission.toShort();
  166.     // get the expected permission
  167.     short expectedPermission = (op == OpType.CREATE) ? (short) (~umask
  168.         & permissionNum & FILE_MASK) : (short) (~umask & permissionNum);
  169.     // check if permission is correctly set
  170.     checkPermission(name, expectedPermission, delete);
  171.   }
  172.   /* Check if the permission of a file/directory is the same as the
  173.    * expected permission; If the delete flag is true, delete the
  174.    * file/directory afterwards.
  175.    */
  176.   private void checkPermission(Path name, short expectedPermission,
  177.       boolean delete) throws IOException {
  178.     try {
  179.       // check its permission
  180.       assertEquals(getPermission(name), expectedPermission);
  181.     } finally {
  182.       // delete the file
  183.       if (delete) {
  184.         fs.delete(name, true);
  185.       }
  186.     }
  187.   }
  188.   /* check if the ownership of a file/directory is set correctly */
  189.   public void testOwnership() throws Exception {
  190.     MiniDFSCluster cluster = new MiniDFSCluster(conf, 3, true, null);
  191.     try {
  192.       cluster.waitActive();
  193.       testOwnership(OpType.CREATE); // test file creation
  194.       testOwnership(OpType.MKDIRS); // test directory creation
  195.     } finally {
  196.       fs.close();
  197.       cluster.shutdown();
  198.     }
  199.   }
  200.   /* change a file/directory's owner and group.
  201.    * if expectDeny is set, expect an AccessControlException.
  202.    */
  203.   private void setOwner(Path path, String owner, String group,
  204.       boolean expectDeny) throws IOException {
  205.     try {
  206.       String expectedOwner = (owner == null) ? getOwner(path) : owner;
  207.       String expectedGroup = (group == null) ? getGroup(path) : group;
  208.       fs.setOwner(path, owner, group);
  209.       checkOwnership(path, expectedOwner, expectedGroup);
  210.       assertFalse(expectDeny);
  211.     } catch(AccessControlException e) {
  212.       assertTrue(expectDeny);
  213.     }
  214.   }
  215.   /* check ownership is set correctly for a file or directory */
  216.   private void testOwnership(OpType op) throws Exception {
  217.     // case 1: superuser create a file/directory
  218.     fs = FileSystem.get(conf);
  219.     create(op, FILE_DIR_PATH, DEFAULT_UMASK,
  220.         new FsPermission(DEFAULT_PERMISSION));
  221.     checkOwnership(FILE_DIR_PATH, SUPERUSER.getUserName(),
  222.         getGroup(FILE_DIR_PATH.getParent()));
  223.     // case 2: superuser changes FILE_DIR_PATH's owner to be <user1, group3>
  224.     setOwner(FILE_DIR_PATH, USER1.getUserName(), GROUP3_NAME, false);
  225.     // case 3: user1 changes FILE_DIR_PATH's owner to be user2
  226.     login(USER1);
  227.     setOwner(FILE_DIR_PATH, USER2.getUserName(), null, true);
  228.     // case 4: user1 changes FILE_DIR_PATH's group to be group1 which it belongs
  229.     // to
  230.     setOwner(FILE_DIR_PATH, null, GROUP1_NAME, false);
  231.     // case 5: user1 changes FILE_DIR_PATH's group to be group3
  232.     // which it does not belong to
  233.     setOwner(FILE_DIR_PATH, null, GROUP3_NAME, true);
  234.     // case 6: user2 (non-owner) changes FILE_DIR_PATH's group to be group3
  235.     login(USER2);
  236.     setOwner(FILE_DIR_PATH, null, GROUP3_NAME, true);
  237.     // case 7: user2 (non-owner) changes FILE_DIR_PATH's user to be user2
  238.     setOwner(FILE_DIR_PATH, USER2.getUserName(), null, true);
  239.     // delete the file/directory
  240.     login(SUPERUSER);
  241.     fs.delete(FILE_DIR_PATH, true);
  242.   }
  243.   /* Return the group owner of the file/directory */
  244.   private String getGroup(Path path) throws IOException {
  245.     return fs.getFileStatus(path).getGroup();
  246.   }
  247.   /* Return the file owner of the file/directory */
  248.   private String getOwner(Path path) throws IOException {
  249.     return fs.getFileStatus(path).getOwner();
  250.   }
  251.   /* check if ownership is set correctly */
  252.   private void checkOwnership(Path name, String expectedOwner,
  253.       String expectedGroup) throws IOException {
  254.     // check its owner and group
  255.     FileStatus status = fs.getFileStatus(name);
  256.     assertEquals(status.getOwner(), expectedOwner);
  257.     assertEquals(status.getGroup(), expectedGroup);
  258.   }
  259.   final static private String ANCESTOR_NAME = "/ancestor";
  260.   final static private String PARENT_NAME = "parent";
  261.   final static private String FILE_NAME = "file";
  262.   final static private String DIR_NAME = "dir";
  263.   final static private String FILE_DIR_NAME = "filedir";
  264.   private enum OpType {CREATE, MKDIRS, OPEN, SET_REPLICATION,
  265.     GET_FILEINFO, IS_DIR, EXISTS, GET_CONTENT_LENGTH, LIST, RENAME, DELETE
  266.   };
  267.   /* Check if namenode performs permission checking correctly for
  268.    * superuser, file owner, group owner, and other users */
  269.   public void testPermissionChecking() throws Exception {
  270.     MiniDFSCluster cluster = new MiniDFSCluster(conf, 3, true, null);
  271.     try {
  272.       cluster.waitActive();
  273.       fs = FileSystem.get(conf);
  274.       // set the permission of the root to be world-wide rwx
  275.       fs.setPermission(new Path("/"), new FsPermission((short)0777));
  276.       
  277.       // create a directory hierarchy and sets random permission for each inode
  278.       PermissionGenerator ancestorPermissionGenerator = 
  279.         new PermissionGenerator(r);
  280.       PermissionGenerator dirPermissionGenerator = new PermissionGenerator(r);
  281.       PermissionGenerator filePermissionGenerator = new PermissionGenerator(r);
  282.       short[] ancestorPermissions = new short[NUM_TEST_PERMISSIONS];
  283.       short[] parentPermissions = new short[NUM_TEST_PERMISSIONS];
  284.       short[] permissions = new short[NUM_TEST_PERMISSIONS];
  285.       Path[] ancestorPaths = new Path[NUM_TEST_PERMISSIONS];
  286.       Path[] parentPaths = new Path[NUM_TEST_PERMISSIONS];
  287.       Path[] filePaths = new Path[NUM_TEST_PERMISSIONS];
  288.       Path[] dirPaths = new Path[NUM_TEST_PERMISSIONS];
  289.       for (int i = 0; i < NUM_TEST_PERMISSIONS; i++) {
  290.         // create ancestor directory
  291.         ancestorPaths[i] = new Path(ANCESTOR_NAME + i);
  292.         create(OpType.MKDIRS, ancestorPaths[i]);
  293.         fs.setOwner(ancestorPaths[i], USER1_NAME, GROUP2_NAME);
  294.         // create parent directory
  295.         parentPaths[i] = new Path(ancestorPaths[i], PARENT_NAME + i);
  296.         create(OpType.MKDIRS, parentPaths[i]);
  297.         // change parent directory's ownership to be user1
  298.         fs.setOwner(parentPaths[i], USER1_NAME, GROUP2_NAME);
  299.         filePaths[i] = new Path(parentPaths[i], FILE_NAME + i);
  300.         dirPaths[i] = new Path(parentPaths[i], DIR_NAME + i);
  301.         // makes sure that each inode at the same level 
  302.         // has a different permission
  303.         ancestorPermissions[i] = ancestorPermissionGenerator.next();
  304.         parentPermissions[i] = dirPermissionGenerator.next();
  305.         permissions[i] = filePermissionGenerator.next();
  306.         fs.setPermission(ancestorPaths[i], new FsPermission(
  307.             ancestorPermissions[i]));
  308.         fs.setPermission(parentPaths[i], new FsPermission(
  309.                 parentPermissions[i]));
  310.       }
  311.       /* file owner */
  312.       testPermissionCheckingPerUser(USER1, ancestorPermissions,
  313.           parentPermissions, permissions, parentPaths, filePaths, dirPaths);
  314.       /* group owner */
  315.       testPermissionCheckingPerUser(USER2, ancestorPermissions,
  316.           parentPermissions, permissions, parentPaths, filePaths, dirPaths);
  317.       /* other owner */
  318.       testPermissionCheckingPerUser(USER3, ancestorPermissions,
  319.           parentPermissions, permissions, parentPaths, filePaths, dirPaths);
  320.       /* super owner */
  321.       testPermissionCheckingPerUser(SUPERUSER, ancestorPermissions,
  322.           parentPermissions, permissions, parentPaths, filePaths, dirPaths);
  323.     } finally {
  324.       fs.close();
  325.       cluster.shutdown();
  326.     }
  327.   }
  328.   /* Check if namenode performs permission checking correctly 
  329.    * for the given user for operations mkdir, open, setReplication, 
  330.    * getFileInfo, isDirectory, exists, getContentLength, list, rename,
  331.    * and delete */
  332.   private void testPermissionCheckingPerUser(UnixUserGroupInformation ugi,
  333.       short[] ancestorPermission, short[] parentPermission,
  334.       short[] filePermission, Path[] parentDirs, Path[] files, Path[] dirs)
  335.       throws Exception {
  336.     login(SUPERUSER);
  337.     for (int i = 0; i < NUM_TEST_PERMISSIONS; i++) {
  338.       create(OpType.CREATE, files[i]);
  339.       create(OpType.MKDIRS, dirs[i]);
  340.       fs.setOwner(files[i], USER1_NAME, GROUP2_NAME);
  341.       fs.setOwner(dirs[i], USER1_NAME, GROUP2_NAME);
  342.       checkOwnership(dirs[i], USER1_NAME, GROUP2_NAME);
  343.       checkOwnership(files[i], USER1_NAME, GROUP2_NAME);
  344.       FsPermission fsPermission = new FsPermission(filePermission[i]);
  345.       fs.setPermission(files[i], fsPermission);
  346.       fs.setPermission(dirs[i], fsPermission);
  347.     }
  348.     login(ugi);
  349.     for (int i = 0; i < NUM_TEST_PERMISSIONS; i++) {
  350.       testCreateMkdirs(ugi, new Path(parentDirs[i], FILE_DIR_NAME),
  351.           ancestorPermission[i], parentPermission[i]);
  352.       testOpen(ugi, files[i], ancestorPermission[i], parentPermission[i],
  353.           filePermission[i]);
  354.       testSetReplication(ugi, files[i], ancestorPermission[i],
  355.           parentPermission[i], filePermission[i]);
  356.       testSetTimes(ugi, files[i], ancestorPermission[i],
  357.           parentPermission[i], filePermission[i]);
  358.       testStats(ugi, files[i], ancestorPermission[i], parentPermission[i]);
  359.       testList(ugi, files[i], dirs[i], ancestorPermission[i],
  360.           parentPermission[i], filePermission[i]);
  361.       int next = i == NUM_TEST_PERMISSIONS - 1 ? 0 : i + 1;
  362.       testRename(ugi, files[i], files[next], ancestorPermission[i],
  363.           parentPermission[i], ancestorPermission[next], parentPermission[next]);
  364.       testDeleteFile(ugi, files[i], ancestorPermission[i], parentPermission[i]);
  365.       testDeleteDir(ugi, dirs[i], ancestorPermission[i], parentPermission[i],
  366.           filePermission[i], null);
  367.     }
  368.     
  369.     // test non existent file
  370.     checkNonExistentFile();
  371.   }
  372.   /* A random permission generator that guarantees that each permission
  373.    * value is generated only once.
  374.    */
  375.   static private class PermissionGenerator {
  376.     private Random r;
  377.     private short permissions[] = new short[MAX_PERMISSION + 1];
  378.     private int numLeft = MAX_PERMISSION + 1;
  379.     PermissionGenerator(Random r) {
  380.       this.r = r;
  381.       for (int i = 0; i <= MAX_PERMISSION; i++) {
  382.         permissions[i] = (short) i;
  383.       }
  384.     }
  385.     short next() throws IOException {
  386.       if (numLeft == 0) {
  387.         throw new IOException("No more permission is avaialbe");
  388.       }
  389.       int index = r.nextInt(numLeft); // choose which permission to return
  390.       numLeft--; // decrement the counter
  391.       // swap the chosen permission with last available permission in the array
  392.       short temp = permissions[numLeft];
  393.       permissions[numLeft] = permissions[index];
  394.       permissions[index] = temp;
  395.       return permissions[numLeft];
  396.     }
  397.   }
  398.   /* A base class that verifies the permission checking is correct 
  399.    * for an operation */
  400.   abstract class PermissionVerifier {
  401.     protected Path path;
  402.     protected short ancestorPermission;
  403.     protected short parentPermission;
  404.     private short permission;
  405.     protected short requiredAncestorPermission;
  406.     protected short requiredParentPermission;
  407.     protected short requiredPermission;
  408.     final static protected short opAncestorPermission = SEARCH_MASK;
  409.     protected short opParentPermission;
  410.     protected short opPermission;
  411.     protected UnixUserGroupInformation ugi;
  412.     /* initialize */
  413.     protected void set(Path path, short ancestorPermission,
  414.         short parentPermission, short permission) {
  415.       this.path = path;
  416.       this.ancestorPermission = ancestorPermission;
  417.       this.parentPermission = parentPermission;
  418.       this.permission = permission;
  419.       setOpPermission();
  420.       this.ugi = null;
  421.     }
  422.     /* Perform an operation and verify if the permission checking is correct */
  423.     void verifyPermission(UnixUserGroupInformation ugi) throws LoginException,
  424.         IOException {
  425.       if (this.ugi != ugi) {
  426.         setRequiredPermissions(ugi);
  427.         this.ugi = ugi;
  428.       }
  429.       try {
  430.         try {
  431.           call();
  432.           assertFalse(expectPermissionDeny());
  433.         } catch(AccessControlException e) {
  434.           assertTrue(expectPermissionDeny());
  435.         }
  436.       } catch (AssertionFailedError ae) {
  437.         logPermissions();
  438.         throw ae;
  439.       }
  440.     }
  441.     /** Log the permissions and required permissions */
  442.     protected void logPermissions() {
  443.       LOG.info("required ancestor permission:"
  444.           + Integer.toOctalString(requiredAncestorPermission));
  445.       LOG.info("ancestor permission: "
  446.           + Integer.toOctalString(ancestorPermission));
  447.       LOG.info("required parent permission:"
  448.           + Integer.toOctalString(requiredParentPermission));
  449.       LOG.info("parent permission: " + Integer.toOctalString(parentPermission));
  450.       LOG.info("required permission:"
  451.           + Integer.toOctalString(requiredPermission));
  452.       LOG.info("permission: " + Integer.toOctalString(permission));
  453.     }
  454.     /* Return true if an AccessControlException is expected */
  455.     protected boolean expectPermissionDeny() {
  456.       return (requiredPermission & permission) != requiredPermission
  457.           || (requiredParentPermission & parentPermission) !=
  458.                             requiredParentPermission
  459.           || (requiredAncestorPermission & ancestorPermission) !=
  460.                             requiredAncestorPermission;
  461.     }
  462.     /* Set the permissions required to pass the permission checking */
  463.     protected void setRequiredPermissions(UnixUserGroupInformation ugi)
  464.         throws IOException {
  465.       if (SUPERUSER.equals(ugi)) {
  466.         requiredAncestorPermission = SUPER_MASK;
  467.         requiredParentPermission = SUPER_MASK;
  468.         requiredPermission = SUPER_MASK;
  469.       } else if (USER1.equals(ugi)) {
  470.         requiredAncestorPermission = (short)(opAncestorPermission & OWNER_MASK);
  471.         requiredParentPermission = (short)(opParentPermission & OWNER_MASK);
  472.         requiredPermission = (short)(opPermission & OWNER_MASK);
  473.       } else if (USER2.equals(ugi)) {
  474.         requiredAncestorPermission = (short)(opAncestorPermission & GROUP_MASK);
  475.         requiredParentPermission = (short)(opParentPermission & GROUP_MASK);
  476.         requiredPermission = (short)(opPermission & GROUP_MASK);
  477.       } else if (USER3.equals(ugi)) {
  478.         requiredAncestorPermission = (short)(opAncestorPermission & OTHER_MASK);
  479.         requiredParentPermission = (short)(opParentPermission & OTHER_MASK);
  480.         requiredPermission = (short)(opPermission & OTHER_MASK);
  481.       } else {
  482.         throw new IllegalArgumentException("Non-supported user: " + ugi);
  483.       }
  484.     }
  485.     /* Set the rwx permissions required for the operation */
  486.     abstract void setOpPermission();
  487.     /* Perform the operation */
  488.     abstract void call() throws IOException;
  489.   }
  490.   final static private short SUPER_MASK = 0;
  491.   final static private short READ_MASK = 0444;
  492.   final static private short WRITE_MASK = 0222;
  493.   final static private short SEARCH_MASK = 0111;
  494.   final static private short NULL_MASK = 0;
  495.   final static private short OWNER_MASK = 0700;
  496.   final static private short GROUP_MASK = 0070;
  497.   final static private short OTHER_MASK = 0007;
  498.   /* A class that verifies the permission checking is correct for create/mkdir*/
  499.   private class CreatePermissionVerifier extends PermissionVerifier {
  500.     private OpType opType;
  501.     private boolean cleanup = true;
  502.     /* initialize */
  503.     protected void set(Path path, OpType opType, short ancestorPermission,
  504.         short parentPermission) {
  505.       super.set(path, ancestorPermission, parentPermission, NULL_MASK);
  506.       setOpType(opType);
  507.     }
  508.     void setCleanup(boolean cleanup) {
  509.       this.cleanup = cleanup;
  510.     }
  511.     
  512.     /* set if the operation mkdir/create */
  513.     void setOpType(OpType opType) {
  514.       this.opType = opType;
  515.     }
  516.     @Override
  517.     void setOpPermission() {
  518.       this.opParentPermission = SEARCH_MASK | WRITE_MASK;
  519.     }
  520.     @Override
  521.     void call() throws IOException {
  522.       create(opType, path);
  523.       if (cleanup) {
  524.         fs.delete(path, true);
  525.       }
  526.     }
  527.   }
  528.   private CreatePermissionVerifier createVerifier =
  529.     new CreatePermissionVerifier();
  530.   /* test if the permission checking of create/mkdir is correct */
  531.   private void testCreateMkdirs(UnixUserGroupInformation ugi, Path path,
  532.       short ancestorPermission, short parentPermission) throws Exception {
  533.     createVerifier.set(path, OpType.MKDIRS, ancestorPermission,
  534.         parentPermission);
  535.     createVerifier.verifyPermission(ugi);
  536.     createVerifier.setOpType(OpType.CREATE);
  537.     createVerifier.setCleanup(false);
  538.     createVerifier.verifyPermission(ugi);
  539.     createVerifier.setCleanup(true);
  540.     createVerifier.verifyPermission(ugi); // test overWritten
  541.   }
  542.   /* A class that verifies the permission checking is correct for open */
  543.   private class OpenPermissionVerifier extends PermissionVerifier {
  544.     @Override
  545.     void setOpPermission() {
  546.       this.opParentPermission = SEARCH_MASK;
  547.       this.opPermission = READ_MASK;
  548.     }
  549.     @Override
  550.     void call() throws IOException {
  551.       FSDataInputStream in = fs.open(path);
  552.       in.close();
  553.     }
  554.   }
  555.   private OpenPermissionVerifier openVerifier = new OpenPermissionVerifier();
  556.   /* test if the permission checking of open is correct */
  557.   private void testOpen(UnixUserGroupInformation ugi, Path path,
  558.       short ancestorPermission, short parentPermission, short filePermission)
  559.       throws Exception {
  560.     openVerifier
  561.         .set(path, ancestorPermission, parentPermission, filePermission);
  562.     openVerifier.verifyPermission(ugi);
  563.   }
  564.   /* A class that verifies the permission checking is correct for 
  565.    * setReplication */
  566.   private class SetReplicationPermissionVerifier extends PermissionVerifier {
  567.     @Override
  568.     void setOpPermission() {
  569.       this.opParentPermission = SEARCH_MASK;
  570.       this.opPermission = WRITE_MASK;
  571.     }
  572.     @Override
  573.     void call() throws IOException {
  574.       fs.setReplication(path, (short) 1);
  575.     }
  576.   }
  577.   private SetReplicationPermissionVerifier replicatorVerifier =
  578.     new SetReplicationPermissionVerifier();
  579.   /* test if the permission checking of setReplication is correct */
  580.   private void testSetReplication(UnixUserGroupInformation ugi, Path path,
  581.       short ancestorPermission, short parentPermission, short filePermission)
  582.       throws Exception {
  583.     replicatorVerifier.set(path, ancestorPermission, parentPermission,
  584.         filePermission);
  585.     replicatorVerifier.verifyPermission(ugi);
  586.   }
  587.   /* A class that verifies the permission checking is correct for 
  588.    * setTimes */
  589.   private class SetTimesPermissionVerifier extends PermissionVerifier {
  590.     @Override
  591.     void setOpPermission() {
  592.       this.opParentPermission = SEARCH_MASK;
  593.       this.opPermission = WRITE_MASK;
  594.     }
  595.     @Override
  596.     void call() throws IOException {
  597.       fs.setTimes(path, 100, 100);
  598.       fs.setTimes(path, -1, 100);
  599.       fs.setTimes(path, 100, -1);
  600.     }
  601.   }
  602.   private SetTimesPermissionVerifier timesVerifier =
  603.     new SetTimesPermissionVerifier();
  604.   /* test if the permission checking of setReplication is correct */
  605.   private void testSetTimes(UnixUserGroupInformation ugi, Path path,
  606.       short ancestorPermission, short parentPermission, short filePermission)
  607.       throws Exception {
  608.     timesVerifier.set(path, ancestorPermission, parentPermission,
  609.         filePermission);
  610.     timesVerifier.verifyPermission(ugi);
  611.   }
  612.   /* A class that verifies the permission checking is correct for isDirectory,
  613.    * exist,  getFileInfo, getContentSummary */
  614.   private class StatsPermissionVerifier extends PermissionVerifier {
  615.     OpType opType;
  616.     /* initialize */
  617.     void set(Path path, OpType opType, short ancestorPermission,
  618.         short parentPermission) {
  619.       super.set(path, ancestorPermission, parentPermission, NULL_MASK);
  620.       setOpType(opType);
  621.     }
  622.     /* set if operation is getFileInfo, isDirectory, exist, getContenSummary */
  623.     void setOpType(OpType opType) {
  624.       this.opType = opType;
  625.     }
  626.     @Override
  627.     void setOpPermission() {
  628.       this.opParentPermission = SEARCH_MASK;
  629.     }
  630.     @Override
  631.     void call() throws IOException {
  632.       switch (opType) {
  633.       case GET_FILEINFO:
  634.         fs.getFileStatus(path);
  635.         break;
  636.       case IS_DIR:
  637.         fs.isDirectory(path);
  638.         break;
  639.       case EXISTS:
  640.         fs.exists(path);
  641.         break;
  642.       case GET_CONTENT_LENGTH:
  643.         fs.getContentSummary(path).getLength();
  644.         break;
  645.       default:
  646.         throw new IllegalArgumentException("Unexpected operation type: "
  647.             + opType);
  648.       }
  649.     }
  650.   }
  651.   private StatsPermissionVerifier statsVerifier = new StatsPermissionVerifier();
  652.   /* test if the permission checking of isDirectory, exist,
  653.    * getFileInfo, getContentSummary is correct */
  654.   private void testStats(UnixUserGroupInformation ugi, Path path,
  655.       short ancestorPermission, short parentPermission) throws Exception {
  656.     statsVerifier.set(path, OpType.GET_FILEINFO, ancestorPermission,
  657.         parentPermission);
  658.     statsVerifier.verifyPermission(ugi);
  659.     statsVerifier.setOpType(OpType.IS_DIR);
  660.     statsVerifier.verifyPermission(ugi);
  661.     statsVerifier.setOpType(OpType.EXISTS);
  662.     statsVerifier.verifyPermission(ugi);
  663.     statsVerifier.setOpType(OpType.GET_CONTENT_LENGTH);
  664.     statsVerifier.verifyPermission(ugi);
  665.   }
  666.   private enum InodeType {
  667.     FILE, DIR
  668.   };
  669.   /* A class that verifies the permission checking is correct for list */
  670.   private class ListPermissionVerifier extends PermissionVerifier {
  671.     private InodeType inodeType;
  672.     /* initialize */
  673.     void set(Path path, InodeType inodeType, short ancestorPermission,
  674.         short parentPermission, short permission) {
  675.       this.inodeType = inodeType;
  676.       super.set(path, ancestorPermission, parentPermission, permission);
  677.     }
  678.     /* set if the given path is a file/directory */
  679.     void setInodeType(Path path, InodeType inodeType) {
  680.       this.path = path;
  681.       this.inodeType = inodeType;
  682.       setOpPermission();
  683.       this.ugi = null;
  684.     }
  685.     @Override
  686.     void setOpPermission() {
  687.       this.opParentPermission = SEARCH_MASK;
  688.       switch (inodeType) {
  689.       case FILE:
  690.         this.opPermission = 0;
  691.         break;
  692.       case DIR:
  693.         this.opPermission = READ_MASK | SEARCH_MASK;
  694.         break;
  695.       default:
  696.         throw new IllegalArgumentException("Illegal inode type: " + inodeType);
  697.       }
  698.     }
  699.     @Override
  700.     void call() throws IOException {
  701.       fs.listStatus(path);
  702.     }
  703.   }
  704.   ListPermissionVerifier listVerifier = new ListPermissionVerifier();
  705.   /* test if the permission checking of list is correct */
  706.   private void testList(UnixUserGroupInformation ugi, Path file, Path dir,
  707.       short ancestorPermission, short parentPermission, short filePermission)
  708.       throws Exception {
  709.     listVerifier.set(file, InodeType.FILE, ancestorPermission,
  710.         parentPermission, filePermission);
  711.     listVerifier.verifyPermission(ugi);
  712.     listVerifier.setInodeType(dir, InodeType.DIR);
  713.     listVerifier.verifyPermission(ugi);
  714.   }
  715.   /* A class that verifies the permission checking is correct for rename */
  716.   private class RenamePermissionVerifier extends PermissionVerifier {
  717.     private Path dst;
  718.     private short dstAncestorPermission;
  719.     private short dstParentPermission;
  720.     /* initialize */
  721.     void set(Path src, short srcAncestorPermission, short srcParentPermission,
  722.         Path dst, short dstAncestorPermission, short dstParentPermission) {
  723.       super.set(src, srcAncestorPermission, srcParentPermission, NULL_MASK);
  724.       this.dst = dst;
  725.       this.dstAncestorPermission = dstAncestorPermission;
  726.       this.dstParentPermission = dstParentPermission;
  727.     }
  728.     @Override
  729.     void setOpPermission() {
  730.       opParentPermission = SEARCH_MASK | WRITE_MASK;
  731.     }
  732.     @Override
  733.     void call() throws IOException {
  734.       fs.rename(path, dst);
  735.     }
  736.     @Override
  737.     protected boolean expectPermissionDeny() {
  738.       return super.expectPermissionDeny()
  739.           || (requiredParentPermission & dstParentPermission) != 
  740.                 requiredParentPermission
  741.           || (requiredAncestorPermission & dstAncestorPermission) != 
  742.                 requiredAncestorPermission;
  743.     }
  744.     protected void logPermissions() {
  745.       super.logPermissions();
  746.       LOG.info("dst ancestor permission: "
  747.           + Integer.toOctalString(dstAncestorPermission));
  748.       LOG.info("dst parent permission: "
  749.           + Integer.toOctalString(dstParentPermission));
  750.     }
  751.   }
  752.   RenamePermissionVerifier renameVerifier = new RenamePermissionVerifier();
  753.   /* test if the permission checking of rename is correct */
  754.   private void testRename(UnixUserGroupInformation ugi, Path src, Path dst,
  755.       short srcAncestorPermission, short srcParentPermission,
  756.       short dstAncestorPermission, short dstParentPermission) throws Exception {
  757.     renameVerifier.set(src, srcAncestorPermission, srcParentPermission, dst,
  758.         dstAncestorPermission, dstParentPermission);
  759.     renameVerifier.verifyPermission(ugi);
  760.   }
  761.   /* A class that verifies the permission checking is correct for delete */
  762.   private class DeletePermissionVerifier extends PermissionVerifier {
  763.     void set(Path path, short ancestorPermission, short parentPermission) {
  764.       super.set(path, ancestorPermission, parentPermission, NULL_MASK);
  765.     }
  766.     @Override
  767.     void setOpPermission() {
  768.       this.opParentPermission = SEARCH_MASK | WRITE_MASK;
  769.     }
  770.     @Override
  771.     void call() throws IOException {
  772.       fs.delete(path, true);
  773.     }
  774.   }
  775.   /* A class that verifies the permission checking is correct for
  776.    * directory deletion */
  777.   private class DeleteDirPermissionVerifier extends DeletePermissionVerifier {
  778.     private short[] childPermissions;
  779.     /* initialize */
  780.     void set(Path path, short ancestorPermission, short parentPermission,
  781.         short permission, short[] childPermissions) {
  782.       set(path, ancestorPermission, parentPermission, permission);
  783.       this.childPermissions = childPermissions;
  784.     }
  785.     @Override
  786.     void setOpPermission() {
  787.       this.opParentPermission = SEARCH_MASK | WRITE_MASK;
  788.       this.opPermission = SEARCH_MASK | WRITE_MASK | READ_MASK;
  789.     }
  790.     @Override
  791.     protected boolean expectPermissionDeny() {
  792.       if (super.expectPermissionDeny()) {
  793.         return true;
  794.       } else {
  795.         if (childPermissions != null) {
  796.           for (short childPermission : childPermissions) {
  797.             if ((requiredPermission & childPermission) != requiredPermission) {
  798.               return true;
  799.             }
  800.           }
  801.         }
  802.         return false;
  803.       }
  804.     }
  805.   }
  806.   DeletePermissionVerifier fileDeletionVerifier =
  807.     new DeletePermissionVerifier();
  808.   /* test if the permission checking of file deletion is correct */
  809.   private void testDeleteFile(UnixUserGroupInformation ugi, Path file,
  810.       short ancestorPermission, short parentPermission) throws Exception {
  811.     fileDeletionVerifier.set(file, ancestorPermission, parentPermission);
  812.     fileDeletionVerifier.verifyPermission(ugi);
  813.   }
  814.   DeleteDirPermissionVerifier dirDeletionVerifier =
  815.     new DeleteDirPermissionVerifier();
  816.   /* test if the permission checking of directory deletion is correct */
  817.   private void testDeleteDir(UnixUserGroupInformation ugi, Path path,
  818.       short ancestorPermission, short parentPermission, short permission,
  819.       short[] childPermissions) throws Exception {
  820.     dirDeletionVerifier.set(path, ancestorPermission, parentPermission,
  821.         permission, childPermissions);
  822.     dirDeletionVerifier.verifyPermission(ugi);
  823.   }
  824.   /* log into dfs as the given user */
  825.   private void login(UnixUserGroupInformation ugi) throws IOException {
  826.     if (fs != null) {
  827.       fs.close();
  828.     }
  829.     UnixUserGroupInformation.saveToConf(conf,
  830.         UnixUserGroupInformation.UGI_PROPERTY_NAME, ugi);
  831.     fs = FileSystem.get(conf); // login as ugi
  832.   }
  833.   /* test non-existent file */
  834.   private void checkNonExistentFile() {
  835.     try {
  836.       assertFalse(fs.exists(NON_EXISTENT_FILE));
  837.     } catch (IOException e) {
  838.       checkNoPermissionDeny(e);
  839.     }
  840.     try {
  841.       fs.open(NON_EXISTENT_FILE);
  842.     } catch (IOException e) {
  843.       checkNoPermissionDeny(e);
  844.     }
  845.     try {
  846.       fs.setReplication(NON_EXISTENT_FILE, (short)4);
  847.     } catch (IOException e) {
  848.       checkNoPermissionDeny(e);
  849.     }
  850.     try {
  851.       fs.getFileStatus(NON_EXISTENT_FILE);
  852.     } catch (IOException e) {
  853.       checkNoPermissionDeny(e);
  854.     }
  855.     try {      
  856.       fs.getContentSummary(NON_EXISTENT_FILE).getLength();
  857.     } catch (IOException e) {
  858.       checkNoPermissionDeny(e);
  859.     }
  860.     try {
  861.       fs.listStatus(NON_EXISTENT_FILE);
  862.     } catch (IOException e) {
  863.       checkNoPermissionDeny(e);
  864.     }
  865.     try {
  866.       fs.delete(NON_EXISTENT_FILE, true);
  867.     } catch (IOException e) {
  868.       checkNoPermissionDeny(e);
  869.     }
  870.     try {
  871.       fs.rename(NON_EXISTENT_FILE, new Path(NON_EXISTENT_FILE+".txt"));
  872.     } catch (IOException e) {
  873.       checkNoPermissionDeny(e);
  874.     }
  875.   }
  876.   
  877.   private void checkNoPermissionDeny(IOException e) {
  878.     assertFalse(e instanceof AccessControlException);
  879.   }
  880. }