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 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 testDeleteTable2() throws Exception {
678    String namespace1 = name.getMethodName() + "1";
679    String namespace2 = name.getMethodName() + "2";
680    String grantUser = name.getMethodName();
681    TableName table = TableName.valueOf(namespace1, name.getMethodName());
682
683    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
684    // grant user table permission
685    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUser, table, READ);
686    // grant user other namespace permission
687    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUser, namespace2, READ);
688    // delete table
689    admin.disableTable(table);
690    admin.deleteTable(table);
691    // grantUser should have namespace2's acl
692    assertFalse(hasUserTableHdfsAcl(aclTable, grantUser, table));
693    assertTrue(hasUserNamespaceHdfsAcl(aclTable, grantUser, namespace2));
694  }
695
696  @Test
697  public void testDeleteNamespace() throws Exception {
698    String grantUserName = name.getMethodName();
699    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
700    String namespace = name.getMethodName();
701    TableName table = TableName.valueOf(namespace, name.getMethodName());
702    String snapshot = namespace + "t1";
703    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
704    // snapshot
705    snapshotAndWait(snapshot, table);
706    // grant namespace permission
707    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
708    // delete table
709    admin.disableTable(table);
710    admin.deleteTable(table);
711    // delete namespace
712    admin.deleteNamespace(namespace);
713    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
714    assertFalse(hasUserNamespaceHdfsAcl(aclTable, grantUserName, namespace));
715    checkUserAclEntry(FS, helper.getPathHelper().getArchiveNsDir(namespace), grantUserName, true,
716      false);
717
718    // check tmp namespace dir does not exist
719    assertFalse(FS.exists(helper.getPathHelper().getTmpNsDir(namespace)));
720    assertFalse(FS.exists(helper.getPathHelper().getDataNsDir(namespace)));
721    // assertFalse(fs.exists(FS, helper.getPathHelper().getMobDataNsDir(namespace)));
722    deleteTable(table);
723  }
724
725  @Test
726  public void testCleanArchiveTableDir() throws Exception {
727    final String grantUserName = name.getMethodName();
728    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
729    String namespace = name.getMethodName();
730    TableName table = TableName.valueOf(namespace, name.getMethodName());
731    String snapshot = namespace + "t1";
732
733    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
734    snapshotAndWait(snapshot, table);
735    TestHDFSAclHelper.grantOnTable(TEST_UTIL, grantUserName, table, READ);
736    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
737
738    // HFileCleaner will not delete archive table directory even if it's a empty directory
739    HFileCleaner cleaner = TEST_UTIL.getHBaseCluster().getMaster().getHFileCleaner();
740    cleaner.choreForTesting();
741    Path archiveTableDir = HFileArchiveUtil.getTableArchivePath(rootDir, table);
742    assertTrue(FS.exists(archiveTableDir));
743    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), grantUserName, true, true);
744
745    // Check SnapshotScannerHDFSAclCleaner method
746    assertTrue(SnapshotScannerHDFSAclCleaner.isArchiveTableDir(archiveTableDir));
747    assertTrue(SnapshotScannerHDFSAclCleaner.isArchiveNamespaceDir(archiveTableDir.getParent()));
748    assertTrue(
749      SnapshotScannerHDFSAclCleaner.isArchiveDataDir(archiveTableDir.getParent().getParent()));
750    assertFalse(SnapshotScannerHDFSAclCleaner
751      .isArchiveDataDir(archiveTableDir.getParent().getParent().getParent()));
752    deleteTable(table);
753  }
754
755  @Test
756  public void testModifyTable1() throws Exception {
757    String namespace = name.getMethodName();
758    TableName table = TableName.valueOf(namespace, name.getMethodName());
759    String snapshot = namespace + "t1";
760
761    String tableUserName = name.getMethodName();
762    User tableUser = User.createUserForTesting(conf, tableUserName, new String[] {});
763    String tableUserName2 = tableUserName + "2";
764    User tableUser2 = User.createUserForTesting(conf, tableUserName2, new String[] {});
765    String tableUserName3 = tableUserName + "3";
766    User tableUser3 = User.createUserForTesting(conf, tableUserName3, new String[] {});
767    String nsUserName = tableUserName + "-ns";
768    User nsUser = User.createUserForTesting(conf, nsUserName, new String[] {});
769    String globalUserName = tableUserName + "-global";
770    User globalUser = User.createUserForTesting(conf, globalUserName, new String[] {});
771    String globalUserName2 = tableUserName + "-global-2";
772    User globalUser2 = User.createUserForTesting(conf, globalUserName2, new String[] {});
773
774    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName, READ);
775    TestHDFSAclHelper.createNamespace(TEST_UTIL, namespace);
776    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsUserName, namespace, READ);
777    TableDescriptor td = TestHDFSAclHelper.createUserScanSnapshotDisabledTable(TEST_UTIL, table);
778    snapshotAndWait(snapshot, table);
779    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName2, READ);
780    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName, table, READ);
781    SecureTestUtil.grantOnTable(TEST_UTIL, tableUserName2, table, TestHDFSAclHelper.COLUMN1, null,
782      READ);
783    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table, WRITE);
784
785    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, -1);
786    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
787    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
788    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, -1);
789    // Global permission is set before table is created, the acl is inherited
790    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, 6);
791    // Global permission is set after table is created, the table dir acl is skip
792    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser2, snapshot, -1);
793
794    // enable user scan snapshot
795    admin.modifyTable(TableDescriptorBuilder.newBuilder(td)
796      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build());
797    // check scan snapshot
798    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, 6);
799    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
800    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
801    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, 6);
802    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, 6);
803    // check acl table storage and ACLs in dirs
804    assertTrue(hasUserGlobalHdfsAcl(aclTable, globalUserName));
805    checkUserAclEntry(FS, helper.getGlobalRootPaths(), globalUserName, true, true);
806    assertTrue(hasUserNamespaceHdfsAcl(aclTable, nsUserName, namespace));
807    checkUserAclEntry(FS, helper.getNamespaceRootPaths(namespace), nsUserName, true, true);
808    assertTrue(hasUserTableHdfsAcl(aclTable, tableUserName, table));
809    checkUserAclEntry(FS, helper.getTableRootPaths(table, false), tableUserName, true, true);
810    for (String user : new String[] { tableUserName2, tableUserName3 }) {
811      assertFalse(hasUserTableHdfsAcl(aclTable, user, table));
812      checkUserAclEntry(FS, helper.getTableRootPaths(table, false), user, false, false);
813    }
814    deleteTable(table);
815  }
816
817  @Test
818  public void testModifyTable2() throws Exception {
819    String namespace = name.getMethodName();
820    TableName table = TableName.valueOf(namespace, name.getMethodName() + ".1");
821    String snapshot = namespace + "t1";
822    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
823
824    String tableUserName = name.getMethodName();
825    User tableUser = User.createUserForTesting(conf, tableUserName, new String[] {});
826    String tableUserName2 = tableUserName + "2";
827    User tableUser2 = User.createUserForTesting(conf, tableUserName2, new String[] {});
828    String tableUserName3 = tableUserName + "3";
829    User tableUser3 = User.createUserForTesting(conf, tableUserName3, new String[] {});
830    String nsUserName = tableUserName + "-ns";
831    User nsUser = User.createUserForTesting(conf, nsUserName, new String[] {});
832    String globalUserName = tableUserName + "-global";
833    User globalUser = User.createUserForTesting(conf, globalUserName, new String[] {});
834    String globalUserName2 = tableUserName + "-global-2";
835    User globalUser2 = User.createUserForTesting(conf, globalUserName2, new String[] {});
836
837    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
838    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName, READ);
839    SecureTestUtil.grantGlobal(TEST_UTIL, globalUserName2, READ);
840    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsUserName, namespace, READ);
841    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName, table, READ);
842    SecureTestUtil.grantOnTable(TEST_UTIL, tableUserName2, table, TestHDFSAclHelper.COLUMN1, null,
843      READ);
844    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table, WRITE);
845
846    SecureTestUtil.grantOnNamespace(TEST_UTIL, tableUserName2, namespace, READ);
847    TestHDFSAclHelper.createTable(TEST_UTIL, table2);
848    TestHDFSAclHelper.grantOnTable(TEST_UTIL, tableUserName3, table2, READ);
849    // disable user scan snapshot
850    admin.modifyTable(TableDescriptorBuilder.newBuilder(admin.getDescriptor(table))
851      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "false").build());
852    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser, snapshot, -1);
853    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser2, snapshot, -1);
854    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, tableUser3, snapshot, -1);
855    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, nsUser, snapshot, -1);
856    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser, snapshot, -1);
857    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, globalUser2, snapshot, -1);
858    // check access
859    String[] users = new String[] { globalUserName, globalUserName2, nsUserName, tableUserName,
860      tableUserName2, tableUserName3 };
861    for (Path path : helper.getTableRootPaths(table, false)) {
862      for (String user : users) {
863        checkUserAclEntry(FS, path, user, false, false);
864      }
865    }
866    String[] nsUsers = new String[] { globalUserName, globalUserName2, nsUserName };
867    for (Path path : helper.getNamespaceRootPaths(namespace)) {
868      checkUserAclEntry(FS, path, tableUserName, false, false);
869      checkUserAclEntry(FS, path, tableUserName2, true, true);
870      checkUserAclEntry(FS, path, tableUserName3, true, false);
871      for (String user : nsUsers) {
872        checkUserAclEntry(FS, path, user, true, true);
873      }
874    }
875    assertTrue(hasUserNamespaceHdfsAcl(aclTable, nsUserName, namespace));
876    assertTrue(hasUserNamespaceHdfsAcl(aclTable, tableUserName2, namespace));
877    assertFalse(hasUserTableHdfsAcl(aclTable, tableUserName, table));
878    deleteTable(table);
879    deleteTable(table2);
880  }
881
882  @Test
883  public void testRestartMaster() throws Exception {
884    final String grantUserName = name.getMethodName();
885    User grantUser = User.createUserForTesting(conf, grantUserName, new String[] {});
886    String namespace = name.getMethodName();
887    TableName table = TableName.valueOf(namespace, name.getMethodName() + ".1");
888    TableName table2 = TableName.valueOf(namespace, name.getMethodName() + ".2");
889    String snapshot = namespace + "t1";
890    admin.createNamespace(NamespaceDescriptor.create(namespace).build());
891
892    // create table2
893    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table2);
894    // make some region files in tmp dir and check if master archive these region correctly
895    Path tmpTableDir = helper.getPathHelper().getTmpTableDir(table2);
896    // make a empty region dir, this is an error region
897    FS.mkdirs(new Path(tmpTableDir, "1"));
898    // copy regions from data dir, this is a valid region
899    for (Path regionDir : FSUtils.getRegionDirs(FS,
900      helper.getPathHelper().getDataTableDir(table2))) {
901      FSUtils.copyFilesParallel(FS, regionDir, FS,
902        new Path(tmpTableDir, regionDir.getName() + "abc"), conf, 1);
903    }
904    assertEquals(4, FS.listStatus(tmpTableDir).length);
905
906    // grant N(R)
907    SecureTestUtil.grantOnNamespace(TEST_UTIL, grantUserName, namespace, READ);
908    // restart cluster and tmp directory will not be deleted
909    TEST_UTIL.getMiniHBaseCluster().shutdown();
910    TEST_UTIL.restartHBaseCluster(1);
911    TEST_UTIL.waitUntilNoRegionsInTransition();
912
913    // reset the cached configs after restart
914    conf = TEST_UTIL.getConfiguration();
915    admin = TEST_UTIL.getAdmin();
916    helper = new SnapshotScannerHDFSAclHelper(conf, admin.getConnection());
917
918    Path tmpNsDir = helper.getPathHelper().getTmpNsDir(namespace);
919    assertTrue(FS.exists(tmpNsDir));
920    // check all regions in tmp table2 dir are archived
921    assertEquals(0, FS.listStatus(tmpTableDir).length);
922
923    // create table1 and snapshot
924    TestHDFSAclHelper.createTableAndPut(TEST_UTIL, table);
925    aclTable = TEST_UTIL.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME);
926    snapshotAndWait(snapshot, table);
927    TestHDFSAclHelper.canUserScanSnapshot(TEST_UTIL, grantUser, snapshot, 6);
928    deleteTable(table);
929    deleteTable(table2);
930  }
931
932  static void checkUserAclEntry(FileSystem fs, List<Path> paths, String user,
933    boolean requireAccessAcl, boolean requireDefaultAcl) throws Exception {
934    for (Path path : paths) {
935      checkUserAclEntry(fs, path, user, requireAccessAcl, requireDefaultAcl);
936    }
937  }
938
939  static void checkUserAclEntry(FileSystem fs, Path path, String userName, boolean requireAccessAcl,
940    boolean requireDefaultAcl) throws IOException {
941    boolean accessAclEntry = false;
942    boolean defaultAclEntry = false;
943    if (fs.exists(path)) {
944      for (AclEntry aclEntry : fs.getAclStatus(path).getEntries()) {
945        String user = aclEntry.getName();
946        if (user != null && user.equals(userName)) {
947          if (aclEntry.getScope() == AclEntryScope.DEFAULT) {
948            defaultAclEntry = true;
949          } else if (aclEntry.getScope() == AclEntryScope.ACCESS) {
950            accessAclEntry = true;
951          }
952        }
953      }
954    }
955    String message = "require user: " + userName + ", path: " + path.toString() + " acl";
956    assertEquals(message, requireAccessAcl, accessAclEntry);
957    assertEquals(message, requireDefaultAcl, defaultAclEntry);
958  }
959
960  static void deleteTable(TableName tableName) {
961    try {
962      admin.disableTable(tableName);
963      admin.deleteTable(tableName);
964    } catch (IOException e) {
965      LOG.warn("Failed to delete table: {}", tableName);
966    }
967  }
968}