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.hbase.security.access;
019
020import static org.apache.hadoop.hbase.security.access.Permission.Action.READ;
021import static org.apache.hadoop.hbase.security.access.Permission.Action.WRITE;
022import static org.apache.hadoop.hbase.security.access.SnapshotScannerHDFSAclController.SnapshotScannerHDFSAclStorage.hasUserGlobalHdfsAcl;
023import static org.apache.hadoop.hbase.security.access.SnapshotScannerHDFSAclController.SnapshotScannerHDFSAclStorage.hasUserNamespaceHdfsAcl;
024import static org.apache.hadoop.hbase.security.access.SnapshotScannerHDFSAclController.SnapshotScannerHDFSAclStorage.hasUserTableHdfsAcl;
025import static org.junit.Assert.assertEquals;
026import static org.junit.Assert.assertFalse;
027import static org.junit.Assert.assertTrue;
028
029import java.io.IOException;
030import java.util.List;
031import org.apache.hadoop.conf.Configuration;
032import org.apache.hadoop.fs.FileSystem;
033import org.apache.hadoop.fs.Path;
034import org.apache.hadoop.fs.permission.AclEntry;
035import org.apache.hadoop.fs.permission.AclEntryScope;
036import org.apache.hadoop.fs.permission.FsPermission;
037import org.apache.hadoop.hbase.HBaseClassTestRule;
038import org.apache.hadoop.hbase.HBaseTestingUtility;
039import org.apache.hadoop.hbase.NamespaceDescriptor;
040import org.apache.hadoop.hbase.TableName;
041import org.apache.hadoop.hbase.client.Admin;
042import org.apache.hadoop.hbase.client.Table;
043import org.apache.hadoop.hbase.client.TableDescriptor;
044import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
045import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
046import org.apache.hadoop.hbase.master.cleaner.HFileCleaner;
047import org.apache.hadoop.hbase.security.User;
048import org.apache.hadoop.hbase.testclassification.LargeTests;
049import org.apache.hadoop.hbase.testclassification.SecurityTests;
050import org.apache.hadoop.hbase.util.FSUtils;
051import org.apache.hadoop.hbase.util.HFileArchiveUtil;
052import org.apache.hadoop.hbase.util.Threads;
053import org.junit.AfterClass;
054import org.junit.BeforeClass;
055import org.junit.ClassRule;
056import org.junit.Rule;
057import org.junit.Test;
058import org.junit.experimental.categories.Category;
059import org.junit.rules.TestName;
060import org.slf4j.Logger;
061import org.slf4j.LoggerFactory;
062
063@Category({ SecurityTests.class, LargeTests.class })
064public class TestSnapshotScannerHDFSAclController {
065  @ClassRule
066  public static final HBaseClassTestRule CLASS_RULE =
067    HBaseClassTestRule.forClass(TestSnapshotScannerHDFSAclController.class);
068  @Rule
069  public TestName name = new TestName();
070  private static final Logger LOG =
071    LoggerFactory.getLogger(TestSnapshotScannerHDFSAclController.class);
072
073  private static final String UN_GRANT_USER = "un_grant_user";
074  private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
075  private static Configuration conf = TEST_UTIL.getConfiguration();
076  private static Admin admin = null;
077  private static FileSystem FS = null;
078  private static Path rootDir = null;
079  private static User unGrantUser = null;
080  private static SnapshotScannerHDFSAclHelper helper;
081  private static Table aclTable;
082
083  @BeforeClass
084  public static void setupBeforeClass() throws Exception {
085    // enable hdfs acl and set umask to 027
086    conf.setBoolean("dfs.namenode.acls.enabled", true);
087    conf.set("fs.permissions.umask-mode", "027");
088    // enable hbase hdfs acl feature
089    conf.setBoolean(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, true);
090    // enable secure
091    conf.set(User.HBASE_SECURITY_CONF_KEY, "simple");
092    conf.set(SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_TMP_DIR,
093      SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_TMP_DIR_DEFAULT);
094    SecureTestUtil.enableSecurity(conf);
095    // add SnapshotScannerHDFSAclController coprocessor
096    conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
097      conf.get(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY) + ","
098        + SnapshotScannerHDFSAclController.class.getName());
099
100    TEST_UTIL.startMiniCluster();
101    SnapshotScannerHDFSAclController coprocessor = TEST_UTIL.getHBaseCluster().getMaster()
102      .getMasterCoprocessorHost().findCoprocessor(SnapshotScannerHDFSAclController.class);
103    TEST_UTIL.waitFor(30000, () -> coprocessor.checkInitialized("check initialized"));
104    TEST_UTIL.waitTableAvailable(PermissionStorage.ACL_TABLE_NAME);
105
106    admin = TEST_UTIL.getAdmin();
107    rootDir = TEST_UTIL.getDefaultRootDirPath();
108    FS = rootDir.getFileSystem(conf);
109    unGrantUser = User.createUserForTesting(conf, UN_GRANT_USER, new String[] {});
110    helper = new SnapshotScannerHDFSAclHelper(conf, admin.getConnection());
111
112    // set hbase directory permission
113    FsPermission commonDirectoryPermission =
114      new FsPermission(conf.get(SnapshotScannerHDFSAclHelper.COMMON_DIRECTORY_PERMISSION,
115        SnapshotScannerHDFSAclHelper.COMMON_DIRECTORY_PERMISSION_DEFAULT));
116    Path path = rootDir;
117    while (path != null) {
118      FS.setPermission(path, commonDirectoryPermission);
119      path = path.getParent();
120    }
121    // set restore directory permission
122    Path restoreDir = new Path(SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_TMP_DIR_DEFAULT);
123    if (!FS.exists(restoreDir)) {
124      FS.mkdirs(restoreDir);
125      FS.setPermission(restoreDir,
126        new FsPermission(
127          conf.get(SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_DIRECTORY_PERMISSION,
128            SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_DIRECTORY_PERMISSION_DEFAULT)));
129    }
130    path = restoreDir.getParent();
131    while (path != null) {
132      FS.setPermission(path, commonDirectoryPermission);
133      path = path.getParent();
134    }
135    aclTable = admin.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME);
136  }
137
138  @AfterClass
139  public static void tearDownAfterClass() throws Exception {
140    TEST_UTIL.shutdownMiniCluster();
141  }
142
143  private void snapshotAndWait(final String snapShotName, final TableName tableName)
144    throws Exception {
145    admin.snapshot(snapShotName, tableName);
146    LOG.info("Sleep for one second, waiting for HDFS Acl setup");
147    Threads.sleep(3000);
148  }
149
150  @Test
151  public void testGrantGlobal1() throws Exception {
152    final String grantUserName = name.getMethodName();
153    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
154    String namespace = name.getMethodName();
155    TableName table = TableName.valueOf(namespace, name.getMethodName());
156    String snapshot1 = namespace + "s1";
157    String snapshot2 = namespace + "s2";
158
159    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
160    snapshotAndWait(snapshot1, table);
161    // grant G(R)
162    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
163    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
164    assertTrue(hasUserGlobalHdfsAcl(aclTable, grantUserName));
165    // grant G(W) with merging existing permissions
166    admin.grant(
167      new UserPermission(grantUserName, Permission.newBuilder().withActions(WRITE).build()), true);
168    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
169    assertTrue(hasUserGlobalHdfsAcl(aclTable, grantUserName));
170    // grant G(W) without merging
171    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, WRITE);
172    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
173    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
174    // grant G(R)
175    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
176    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
177    // take a snapshot and ACLs are inherited automatically
178    snapshotAndWait(snapshot2, table);
179    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, 6);
180    assertTrue(hasUserGlobalHdfsAcl(aclTable, grantUserName));
181    deleteTable(table);
182  }
183
184  @Test
185  public void testGrantGlobal2() throws Exception {
186    final String grantUserName = name.getMethodName();
187    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
188    String namespace1 = name.getMethodName();
189    TableName table1 = TableName.valueOf(namespace1, name.getMethodName() + ".1");
190    String namespace2 = namespace1 + "2";
191    TableName table2 = TableName.valueOf(namespace2, name.getMethodName() + ".2");
192    String snapshot1 = namespace1 + "s1";
193    String snapshot2 = namespace2 + "s2";
194
195    // grant G(R), grant namespace1(R)
196    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
197    // create table in namespace1 and snapshot
198    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
199    snapshotAndWait(snapshot1, table1);
200    admin.grant(new UserPermission(grantUserName,
201      Permission.newBuilder(namespace1).withActions(READ).build()), false);
202    // grant G(W)
203    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, WRITE);
204    // create table in namespace2 and snapshot
205    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table2);
206    snapshotAndWait(snapshot2, table2);
207    // check scan snapshot
208    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
209    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, -1);
210    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
211    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace1));
212    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace2));
213    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, false, false);
214    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace1), grantUserName, true, true);
215    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace2), grantUserName, false, false);
216    deleteTable(table1);
217    deleteTable(table2);
218  }
219
220  @Test
221  public void testGrantGlobal3() throws Exception {
222    final String grantUserName = name.getMethodName();
223    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
224    String namespace = name.getMethodName();
225    TableName table1 = TableName.valueOf(namespace, name.getMethodName() + ".1");
226    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
227    String snapshot1 = namespace + "s1";
228    String snapshot2 = namespace + "s2";
229    // grant G(R)
230    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
231    // grant table1(R)
232    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
233    snapshotAndWait(snapshot1, table1);
234    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, READ);
235    // grant G(W)
236    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, WRITE);
237    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table2);
238    snapshotAndWait(snapshot2, table2);
239    // check scan snapshot
240    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
241    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, -1);
242    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
243    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
244    assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
245    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table2));
246    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, false, false);
247    checkUserAclEntry(FS, helper.getTableRootPaths(table2, false), grantUserName, false, false);
248    checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, true, true);
249    deleteTable(table1);
250    deleteTable(table2);
251  }
252
253  @Test
254  public void testGrantNamespace1() throws Exception {
255    final String grantUserName = name.getMethodName();
256    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
257    String namespace = name.getMethodName();
258    TableName table1 = TableName.valueOf(namespace, name.getMethodName() + ".1");
259    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
260    String snapshot1 = namespace + "s1";
261    String snapshot2 = namespace + "s2";
262
263    // create table1 and snapshot
264    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
265    snapshotAndWait(snapshot1, table1);
266    // grant N(R)
267    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
268    // create table2 and snapshot, ACLs can be inherited automatically
269    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table2);
270    snapshotAndWait(snapshot2, table2);
271    // check scan snapshot
272    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
273    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, 6);
274    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, unGrantUser, snapshot1, -1);
275    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
276    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
277    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, true);
278    // grant N(W)
279    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, WRITE);
280    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
281    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
282    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, false, false);
283    deleteTable(table1);
284    deleteTable(table2);
285  }
286
287  @Test
288  public void testGrantNamespace2() throws Exception {
289    final String grantUserName = name.getMethodName();
290    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
291    String namespace = name.getMethodName();
292    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
293    String snapshot1 = namespace + "s1";
294
295    // create table1 and snapshot
296    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
297    snapshotAndWait(snapshot1, table1);
298
299    // grant N(R)
300    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
301    // grant table1(R)
302    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, READ);
303    // grant N(W)
304    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, WRITE);
305    // check scan snapshot
306    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
307    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
308    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, false);
309    assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
310    checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, true, true);
311    deleteTable(table1);
312  }
313
314  @Test
315  public void testGrantNamespace3() throws Exception {
316    final String grantUserName = name.getMethodName();
317    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
318    String namespace = name.getMethodName();
319    TableName table = TableName.valueOf(namespace, name.getMethodName());
320    String snapshot = namespace + "t1";
321
322    // create table1 and snapshot
323    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
324    snapshotAndWait(snapshot, table);
325    // grant namespace(R)
326    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
327    // grant global(R)
328    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
329    // grant namespace(W)
330    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, WRITE);
331    // check scan snapshot
332    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
333    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
334    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, true);
335    assertTrue(hasUserGlobalHdfsAcl(aclTable, grantUserName));
336    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, true, true);
337    deleteTable(table);
338  }
339
340  @Test
341  public void testGrantTable() throws Exception {
342    final String grantUserName = name.getMethodName();
343    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
344
345    String namespace = name.getMethodName();
346    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
347    String snapshot1 = namespace + "s1";
348    String snapshot2 = namespace + "s2";
349
350    LOG.info("Create table");
351    try (Table t = TestHDFSAclHelper.createTable(TEST_UTIL, table1)) {
352      TestHDFSAclHelper.put(t);
353      snapshotAndWait(snapshot1, table1);
354      // table owner can scan table snapshot
355      LOG.info("Scan snapshot");
356      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL,
357        User.createUserForTesting(conf, "owner", new String[] {}), snapshot1, 6);
358      // grant table1 family(R)
359      SecureTestUtil.grantOnTable(TEST_UTIL, grantUserName, table1, TestHDFSAclHelper.COLUMN1, null,
360        READ);
361      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
362
363      // grant table1(R)
364      TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, READ);
365      TestHDFSAclHelper.put2(t);
366      snapshotAndWait(snapshot2, table1);
367
368      // check scan snapshot
369      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
370      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, 10);
371      assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
372      checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, true, true);
373    }
374
375    // grant table1(W) with merging existing permissions
376    admin.grant(
377      new UserPermission(grantUserName, Permission.newBuilder(table1).withActions(WRITE).build()),
378      true);
379    assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
380    checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, true, true);
381
382    // grant table1(W) without merging existing permissions
383    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, WRITE);
384    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
385    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
386    checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, false, false);
387    deleteTable(table1);
388  }
389
390  @Test
391  public void testGrantMobTable() throws Exception {
392    final String grantUserName = name.getMethodName();
393    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
394    String namespace = name.getMethodName();
395    TableName table = TableName.valueOf(namespace, name.getMethodName());
396    String snapshot = namespace + "s1";
397
398    try (Table t = TestHDFSAclHelper.createMobTable(TEST_UTIL, table)) {
399      TestHDFSAclHelper.put(t);
400      snapshotAndWait(snapshot, table);
401      TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
402      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
403      assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table));
404      checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
405    }
406    deleteTable(table);
407  }
408
409  @Test
410  public void testRevokeGlobal1() throws Exception {
411    final String grantUserName = name.getMethodName();
412    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
413    String namespace = name.getMethodName();
414    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
415    String snapshot1 = namespace + "t1";
416
417    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
418    snapshotAndWait(snapshot1, table1);
419    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
420    SecureTestUtil.revokeGlobal(TEST_UTIL, grantUserName, READ);
421    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
422    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
423    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, false, false);
424    deleteTable(table1);
425  }
426
427  @Test
428  public void testRevokeGlobal2() throws Exception {
429    final String grantUserName = name.getMethodName();
430    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
431
432    String namespace = name.getMethodName();
433    String snapshot1 = namespace + "s1";
434    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
435    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
436    snapshotAndWait(snapshot1, table1);
437
438    // grant G(R), grant N(R), grant T(R) -> revoke G(R)
439    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
440    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
441    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, READ);
442    SecureTestUtil.revokeGlobal(TEST_UTIL, grantUserName, READ);
443    // check scan snapshot
444    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
445    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
446    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, false, false);
447    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
448    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, true);
449    deleteTable(table1);
450  }
451
452  @Test
453  public void testRevokeGlobal3() throws Exception {
454    final String grantUserName = name.getMethodName();
455    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
456
457    String namespace = name.getMethodName();
458    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
459    String snapshot1 = namespace + "t1";
460    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
461    snapshotAndWait(snapshot1, table1);
462
463    // grant G(R), grant T(R) -> revoke G(R)
464    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
465    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table1, READ);
466    SecureTestUtil.revokeGlobal(TEST_UTIL, grantUserName, READ);
467    // check scan snapshot
468    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
469    assertFalse(hasUserGlobalHdfsAcl(aclTable, grantUserName));
470    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, false, false);
471    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
472    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, false);
473    assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table1));
474    checkUserAclEntry(FS, helper.getTableRootPaths(table1, false), grantUserName, true, true);
475    deleteTable(table1);
476  }
477
478  @Test
479  public void testRevokeNamespace1() throws Exception {
480    String grantUserName = name.getMethodName();
481    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
482    String namespace = name.getMethodName();
483    TableName table1 = TableName.valueOf(namespace, name.getMethodName());
484    String snapshot1 = namespace + "s1";
485    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table1);
486    snapshotAndWait(snapshot1, table1);
487
488    // revoke N(R)
489    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
490    admin.revoke(new UserPermission(grantUserName, Permission.newBuilder(namespace).build()));
491    // check scan snapshot
492    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, -1);
493    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
494    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, false, false);
495
496    // grant N(R), grant G(R) -> revoke N(R)
497    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
498    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
499    admin.revoke(new UserPermission(grantUserName, Permission.newBuilder(namespace).build()));
500    // check scan snapshot
501    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot1, 6);
502    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
503    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, true);
504    deleteTable(table1);
505  }
506
507  @Test
508  public void testRevokeNamespace2() throws Exception {
509    String grantUserName = name.getMethodName();
510    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
511    String namespace = name.getMethodName();
512    TableName table = TableName.valueOf(namespace, name.getMethodName());
513    String snapshot = namespace + "s1";
514    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
515    snapshotAndWait(snapshot, table);
516
517    // grant N(R), grant T(R) -> revoke N(R)
518    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
519    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
520    SecureTestUtil.revokeFromNamespace(TEST_UTIL, grantUserName, namespace, READ);
521    // check scan snapshot
522    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
523    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
524    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, false);
525    assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, table));
526    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
527    deleteTable(table);
528  }
529
530  @Test
531  public void testRevokeTable1() throws Exception {
532    final String grantUserName = name.getMethodName();
533    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
534    String namespace = name.getMethodName();
535    TableName table = TableName.valueOf(namespace, name.getMethodName());
536    String snapshot = namespace + "t1";
537    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
538    snapshotAndWait(snapshot, table);
539
540    // grant T(R) -> revoke table family
541    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
542    SecureTestUtil.revokeFromTable(TEST_UTIL, grantUserName, table, TestHDFSAclHelper.COLUMN1, null,
543      READ);
544    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
545
546    // grant T(R) -> revoke T(R)
547    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
548    admin.revoke(new UserPermission(grantUserName, Permission.newBuilder(table).build()));
549    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, -1);
550    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table));
551    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, false, false);
552    deleteTable(table);
553  }
554
555  @Test
556  public void testRevokeTable2() throws Exception {
557    final String grantUserName = name.getMethodName();
558    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
559    String namespace = name.getMethodName();
560    TableName table = TableName.valueOf(namespace, name.getMethodName());
561    String snapshot = namespace + "t1";
562    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
563    snapshotAndWait(snapshot, table);
564
565    // grant T(R), grant N(R) -> revoke T(R)
566    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
567    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
568    admin.revoke(new UserPermission(grantUserName, Permission.newBuilder(table).build()));
569    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
570    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table));
571    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
572    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
573    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, true);
574    deleteTable(table);
575  }
576
577  @Test
578  public void testRevokeTable3() throws Exception {
579    final String grantUserName = name.getMethodName();
580    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
581    String namespace = name.getMethodName();
582    TableName table = TableName.valueOf(namespace, name.getMethodName());
583    String snapshot = namespace + "t1";
584    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
585    snapshotAndWait(snapshot, table);
586
587    // grant T(R), grant G(R) -> revoke T(R)
588    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
589    SecureTestUtil.grantGlobal(TEST_UTIL, grantUserName, READ);
590    admin.revoke(new UserPermission(grantUserName, Permission.newBuilder(table).build()));
591    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
592    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName, table));
593    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
594    assertTrue(hasUserGlobalHdfsAcl(aclTable, grantUserName));
595    checkUserAclEntry(FS, helper.getGlobalRootPaths(), grantUserName, true, true);
596    deleteTable(table);
597  }
598
599  @Test
600  public void testTruncateTable() throws Exception {
601    String grantUserName = name.getMethodName();
602    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
603    String grantUserName2 = grantUserName + "2";
604    User grantUser2 = User.createUserForTesting(conf, grantUserName2, new String[] {});
605
606    String namespace = name.getMethodName();
607    TableName tableName = TableName.valueOf(namespace, name.getMethodName());
608    String snapshot = namespace + "s1";
609    String snapshot2 = namespace + "s2";
610    try (Table t = TestHDFSAclHelper.createTable(TEST_UTIL, tableName)) {
611      TestHDFSAclHelper.put(t);
612      // snapshot
613      snapshotAndWait(snapshot, tableName);
614      // grant user2 namespace permission
615      SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName2, namespace, READ);
616      // grant user table permission
617      TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, tableName, READ);
618      // truncate table
619      admin.disableTable(tableName);
620      admin.truncateTable(tableName, true);
621      TestHDFSAclHelper.put2(t);
622      // snapshot
623      snapshotAndWait(snapshot2, tableName);
624      // check scan snapshot
625      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
626      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser2, snapshot, 6);
627      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot2, 9);
628      TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser2, snapshot2, 9);
629      assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName2, namespace));
630      checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName2, true, true);
631      assertTrue(hasUserTableHdfsAcl(aclTable, grantUserName, tableName));
632      checkUserAclEntry(FS, helper.getTableRootPaths(tableName, false), grantUserName, true, true);
633      checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName, true, false);
634    }
635    deleteTable(tableName);
636  }
637
638  @Test
639  public void testDeleteTable() throws Exception {
640    String namespace = name.getMethodName();
641    String grantUserName1 = namespace + "1";
642    String grantUserName2 = namespace + "2";
643    User grantUser1 = User.createUserForTesting(conf, grantUserName1, new String[] {});
644    User grantUser2 = User.createUserForTesting(conf, grantUserName2, new String[] {});
645    TableName table = TableName.valueOf(namespace, name.getMethodName());
646    String snapshot1 = namespace + "t1";
647
648    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
649    // snapshot
650    snapshotAndWait(snapshot1, table);
651    // grant user table permission
652    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName1, table, READ);
653    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName2, namespace, READ);
654    // delete table
655    admin.disableTable(table);
656    admin.deleteTable(table);
657    // grantUser2 and grantUser3 should have data/ns acl
658    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser1, snapshot1, -1);
659    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser2, snapshot1, 6);
660    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUserName2, namespace));
661    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), grantUserName2, true, true);
662    assertFalse(hasUserTableHdfsAcl(aclTable, grantUserName1, table));
663    checkUserAclEntry(FS, helper.getPathHelper().getDataTableDir(table), grantUserName1, false,
664      false);
665    checkUserAclEntry(FS, helper.getPathHelper().getMobTableDir(table), grantUserName1, false,
666      false);
667    checkUserAclEntry(FS, helper.getPathHelper().getArchiveTableDir(table), grantUserName1, true,
668      false);
669
670    // check tmp table directory does not exist
671    Path tmpTableDir = helper.getPathHelper().getTmpTableDir(table);
672    assertFalse(FS.exists(tmpTableDir));
673    deleteTable(table);
674  }
675
676  @Test
677  public void testDeleteNamespace() throws Exception {
678    String grantUserName = name.getMethodName();
679    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
680    String namespace = name.getMethodName();
681    TableName table = TableName.valueOf(namespace, name.getMethodName());
682    String snapshot = namespace + "t1";
683    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
684    // snapshot
685    snapshotAndWait(snapshot, table);
686    // grant namespace permission
687    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
688    // delete table
689    admin.disableTable(table);
690    admin.deleteTable(table);
691    // delete namespace
692    admin.deleteNamespace(namespace);
693    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
694    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
695    checkUserAclEntry(FS, helper.getPathHelper().getArchiveNsDir(namespace), grantUserName, true,
696      false);
697
698    // check tmp namespace dir does not exist
699    assertFalse(FS.exists(helper.getPathHelper().getTmpNsDir(namespace)));
700    assertFalse(FS.exists(helper.getPathHelper().getDataNsDir(namespace)));
701    // assertFalse(fs.exists(FS, helper.getPathHelper().getMobDataNsDir(namespace)));
702    deleteTable(table);
703  }
704
705  @Test
706  public void testCleanArchiveTableDir() throws Exception {
707    final String grantUserName = name.getMethodName();
708    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
709    String namespace = name.getMethodName();
710    TableName table = TableName.valueOf(namespace, name.getMethodName());
711    String snapshot = namespace + "t1";
712
713    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
714    snapshotAndWait(snapshot, table);
715    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
716    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
717
718    // HFileCleaner will not delete archive table directory even if it's a empty directory
719    HFileCleaner cleaner = TEST_UTIL.getHBaseCluster().getMaster().getHFileCleaner();
720    cleaner.choreForTesting();
721    Path archiveTableDir = HFileArchiveUtil.getTableArchivePath(rootDir, table);
722    assertTrue(FS.exists(archiveTableDir));
723    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
724
725    // Check SnapshotScannerHDFSAclCleaner method
726    assertTrue(SnapshotScannerHDFSAclCleaner.isArchiveTableDir(archiveTableDir));
727    assertTrue(SnapshotScannerHDFSAclCleaner.isArchiveNamespaceDir(archiveTableDir.getParent()));
728    assertTrue(
729      SnapshotScannerHDFSAclCleaner.isArchiveDataDir(archiveTableDir.getParent().getParent()));
730    assertFalse(SnapshotScannerHDFSAclCleaner
731      .isArchiveDataDir(archiveTableDir.getParent().getParent().getParent()));
732    deleteTable(table);
733  }
734
735  @Test
736  public void testModifyTable1() throws Exception {
737    String namespace = name.getMethodName();
738    TableName table = TableName.valueOf(namespace, name.getMethodName());
739    String snapshot = namespace + "t1";
740
741    String tableUserName = name.getMethodName();
742    User tableUser = User.createUserForTesting(conf, tableUserName, new String[] {});
743    String tableUserName2 = tableUserName + "2";
744    User tableUser2 = User.createUserForTesting(conf, tableUserName2, new String[] {});
745    String tableUserName3 = tableUserName + "3";
746    User tableUser3 = User.createUserForTesting(conf, tableUserName3, new String[] {});
747    String nsUserName = tableUserName + "-ns";
748    User nsUser = User.createUserForTesting(conf, nsUserName, new String[] {});
749    String globalUserName = tableUserName + "-global";
750    User globalUser = User.createUserForTesting(conf, globalUserName, new String[] {});
751    String globalUserName2 = tableUserName + "-global-2";
752    User globalUser2 = User.createUserForTesting(conf, globalUserName2, new String[] {});
753
754    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName, READ);
755    TestHDFSAclHelper.createNamespace(TEST_UTIL, namespace);
756    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsUserName, namespace, READ);
757    TableDescriptor td = TestHDFSAclHelper.createUserScanSnapshotDisabledTable(TEST_UTIL, table);
758    snapshotAndWait(snapshot, table);
759    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName2, READ);
760    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName, table, READ);
761    SecureTestUtil.grantOnTable(TEST_UTIL, tableUserName2, table, TestHDFSAclHelper.COLUMN1, null,
762      READ);
763    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table, WRITE);
764
765    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, -1);
766    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
767    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
768    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, -1);
769    // Global permission is set before table is created, the acl is inherited
770    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, 6);
771    // Global permission is set after table is created, the table dir acl is skip
772    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser2, snapshot, -1);
773
774    // enable user scan snapshot
775    admin.modifyTable(TableDescriptorBuilder.newBuilder(td)
776      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build());
777    // check scan snapshot
778    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, 6);
779    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
780    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
781    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, 6);
782    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, 6);
783    // check acl table storage and ACLs in dirs
784    assertTrue(hasUserGlobalHdfsAcl(aclTable, globalUserName));
785    checkUserAclEntry(FS, helper.getGlobalRootPaths(), globalUserName, true, true);
786    assertTrue(hasUserNamespaceHdfsAcl(aclTable, nsUserName, namespace));
787    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), nsUserName, true, true);
788    assertTrue(hasUserTableHdfsAcl(aclTable, tableUserName, table));
789    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), tableUserName, true, true);
790    for (String user : new String[] { tableUserName2, tableUserName3 }) {
791      assertFalse(hasUserTableHdfsAcl(aclTable, user, table));
792      checkUserAclEntry(FS, helper.getTableRootPaths(table, false), user, false, false);
793    }
794    deleteTable(table);
795  }
796
797  @Test
798  public void testModifyTable2() throws Exception {
799    String namespace = name.getMethodName();
800    TableName table = TableName.valueOf(namespace, name.getMethodName() + ".1");
801    String snapshot = namespace + "t1";
802    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
803
804    String tableUserName = name.getMethodName();
805    User tableUser = User.createUserForTesting(conf, tableUserName, new String[] {});
806    String tableUserName2 = tableUserName + "2";
807    User tableUser2 = User.createUserForTesting(conf, tableUserName2, new String[] {});
808    String tableUserName3 = tableUserName + "3";
809    User tableUser3 = User.createUserForTesting(conf, tableUserName3, new String[] {});
810    String nsUserName = tableUserName + "-ns";
811    User nsUser = User.createUserForTesting(conf, nsUserName, new String[] {});
812    String globalUserName = tableUserName + "-global";
813    User globalUser = User.createUserForTesting(conf, globalUserName, new String[] {});
814    String globalUserName2 = tableUserName + "-global-2";
815    User globalUser2 = User.createUserForTesting(conf, globalUserName2, new String[] {});
816
817    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
818    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName, READ);
819    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName2, READ);
820    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsUserName, namespace, READ);
821    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName, table, READ);
822    SecureTestUtil.grantOnTable(TEST_UTIL, tableUserName2, table, TestHDFSAclHelper.COLUMN1, null,
823      READ);
824    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table, WRITE);
825
826    SecureTestUtil.grantOnNamespace(TEST_UTIL, tableUserName2, namespace, READ);
827    TestHDFSAclHelper.createTable(TEST_UTIL, table2);
828    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table2, READ);
829    // disable user scan snapshot
830    admin.modifyTable(TableDescriptorBuilder.newBuilder(admin.getDescriptor(table))
831      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "false").build());
832    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, -1);
833    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
834    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
835    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, -1);
836    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, -1);
837    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser2, snapshot, -1);
838    // check access
839    String[] users = new String[] { globalUserName, globalUserName2, nsUserName, tableUserName,
840      tableUserName2, tableUserName3 };
841    for (Path path : helper.getTableRootPaths(table, false)) {
842      for (String user : users) {
843        checkUserAclEntry(FS, path, user, false, false);
844      }
845    }
846    String[] nsUsers = new String[] { globalUserName, globalUserName2, nsUserName };
847    for (Path path : helper.getNamespaceRootPaths(namespace)) {
848      checkUserAclEntry(FS, path, tableUserName, false, false);
849      checkUserAclEntry(FS, path, tableUserName2, true, true);
850      checkUserAclEntry(FS, path, tableUserName3, true, false);
851      for (String user : nsUsers) {
852        checkUserAclEntry(FS, path, user, true, true);
853      }
854    }
855    assertTrue(hasUserNamespaceHdfsAcl(aclTable, nsUserName, namespace));
856    assertTrue(hasUserNamespaceHdfsAcl(aclTable, tableUserName2, namespace));
857    assertFalse(hasUserTableHdfsAcl(aclTable, tableUserName, table));
858    deleteTable(table);
859    deleteTable(table2);
860  }
861
862  @Test
863  public void testRestartMaster() throws Exception {
864    final String grantUserName = name.getMethodName();
865    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
866    String namespace = name.getMethodName();
867    TableName table = TableName.valueOf(namespace, name.getMethodName() + ".1");
868    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
869    String snapshot = namespace + "t1";
870    admin.createNamespace(NamespaceDescriptor.create(namespace).build());
871
872    // create table2
873    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table2);
874    // make some region files in tmp dir and check if master archive these region correctly
875    Path tmpTableDir = helper.getPathHelper().getTmpTableDir(table2);
876    // make a empty region dir, this is an error region
877    FS.mkdirs(new Path(tmpTableDir, "1"));
878    // copy regions from data dir, this is a valid region
879    for (Path regionDir : FSUtils.getRegionDirs(FS,
880      helper.getPathHelper().getDataTableDir(table2))) {
881      FSUtils.copyFilesParallel(FS, regionDir, FS,
882        new Path(tmpTableDir, regionDir.getName() + "abc"), conf, 1);
883    }
884    assertEquals(4, FS.listStatus(tmpTableDir).length);
885
886    // grant N(R)
887    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
888    // restart cluster and tmp directory will not be deleted
889    TEST_UTIL.getMiniHBaseCluster().shutdown();
890    TEST_UTIL.restartHBaseCluster(1);
891    TEST_UTIL.waitUntilNoRegionsInTransition();
892
893    // reset the cached configs after restart
894    conf = TEST_UTIL.getConfiguration();
895    admin = TEST_UTIL.getAdmin();
896    helper = new SnapshotScannerHDFSAclHelper(conf, admin.getConnection());
897
898    Path tmpNsDir = helper.getPathHelper().getTmpNsDir(namespace);
899    assertTrue(FS.exists(tmpNsDir));
900    // check all regions in tmp table2 dir are archived
901    assertEquals(0, FS.listStatus(tmpTableDir).length);
902
903    // create table1 and snapshot
904    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
905    aclTable = TEST_UTIL.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME);
906    snapshotAndWait(snapshot, table);
907    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
908    deleteTable(table);
909    deleteTable(table2);
910  }
911
912  static void checkUserAclEntry(FileSystem fs, List<Path> paths, String user,
913    boolean requireAccessAcl, boolean requireDefaultAcl) throws Exception {
914    for (Path path : paths) {
915      checkUserAclEntry(fs, path, user, requireAccessAcl, requireDefaultAcl);
916    }
917  }
918
919  static void checkUserAclEntry(FileSystem fs, Path path, String userName, boolean requireAccessAcl,
920    boolean requireDefaultAcl) throws IOException {
921    boolean accessAclEntry = false;
922    boolean defaultAclEntry = false;
923    if (fs.exists(path)) {
924      for (AclEntry aclEntry : fs.getAclStatus(path).getEntries()) {
925        String user = aclEntry.getName();
926        if (user != null && user.equals(userName)) {
927          if (aclEntry.getScope() == AclEntryScope.DEFAULT) {
928            defaultAclEntry = true;
929          } else if (aclEntry.getScope() == AclEntryScope.ACCESS) {
930            accessAclEntry = true;
931          }
932        }
933      }
934    }
935    String message = "require user: " + userName + ", path: " + path.toString() + " acl";
936    assertEquals(message, requireAccessAcl, accessAclEntry);
937    assertEquals(message, requireDefaultAcl, defaultAclEntry);
938  }
939
940  static void deleteTable(TableName tableName) {
941    try {
942      admin.disableTable(tableName);
943      admin.deleteTable(tableName);
944    } catch (IOException e) {
945      LOG.warn("Failed to delete table: {}", tableName);
946    }
947  }
948}