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