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.AuthUtil.toGroupEntry;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023import static org.junit.Assert.assertNotNull;
024import static org.junit.Assert.assertTrue;
025
026import java.util.Arrays;
027import java.util.List;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.hbase.Coprocessor;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.HBaseTestingUtil;
032import org.apache.hadoop.hbase.HConstants;
033import org.apache.hadoop.hbase.NamespaceDescriptor;
034import org.apache.hadoop.hbase.TableName;
035import org.apache.hadoop.hbase.TableNameTestRule;
036import org.apache.hadoop.hbase.TableNotFoundException;
037import org.apache.hadoop.hbase.client.Admin;
038import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
039import org.apache.hadoop.hbase.client.Connection;
040import org.apache.hadoop.hbase.client.ConnectionFactory;
041import org.apache.hadoop.hbase.client.Put;
042import org.apache.hadoop.hbase.client.Result;
043import org.apache.hadoop.hbase.client.ResultScanner;
044import org.apache.hadoop.hbase.client.Scan;
045import org.apache.hadoop.hbase.client.Table;
046import org.apache.hadoop.hbase.client.TableDescriptor;
047import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
048import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
049import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
050import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
051import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
052import org.apache.hadoop.hbase.security.User;
053import org.apache.hadoop.hbase.security.access.Permission.Action;
054import org.apache.hadoop.hbase.testclassification.MediumTests;
055import org.apache.hadoop.hbase.testclassification.SecurityTests;
056import org.apache.hadoop.hbase.util.Bytes;
057import org.apache.hadoop.hbase.zookeeper.ZKUtil;
058import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
059import org.junit.After;
060import org.junit.AfterClass;
061import org.junit.Before;
062import org.junit.BeforeClass;
063import org.junit.ClassRule;
064import org.junit.Rule;
065import org.junit.Test;
066import org.junit.experimental.categories.Category;
067import org.slf4j.Logger;
068import org.slf4j.LoggerFactory;
069
070@Category({ SecurityTests.class, MediumTests.class })
071public class TestAccessController2 extends SecureTestUtil {
072
073  @ClassRule
074  public static final HBaseClassTestRule CLASS_RULE =
075    HBaseClassTestRule.forClass(TestAccessController2.class);
076
077  private static final Logger LOG = LoggerFactory.getLogger(TestAccessController2.class);
078
079  private static final byte[] TEST_ROW = Bytes.toBytes("test");
080  private static final byte[] TEST_FAMILY = Bytes.toBytes("f");
081  private static final byte[] TEST_QUALIFIER = Bytes.toBytes("q");
082  private static final byte[] TEST_VALUE = Bytes.toBytes("value");
083
084  private static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
085  private static Configuration conf;
086
087  /**
088   * The systemUserConnection created here is tied to the system user. In case, you are planning to
089   * create AccessTestAction, DON'T use this systemUserConnection as the 'doAs' user gets eclipsed
090   * by the system user.
091   */
092  private static Connection systemUserConnection;
093
094  private final static byte[] Q1 = Bytes.toBytes("q1");
095  private final static byte[] value1 = Bytes.toBytes("value1");
096
097  private static byte[] TEST_FAMILY_2 = Bytes.toBytes("f2");
098  private static byte[] TEST_ROW_2 = Bytes.toBytes("r2");
099  private final static byte[] Q2 = Bytes.toBytes("q2");
100  private final static byte[] value2 = Bytes.toBytes("value2");
101
102  private static byte[] TEST_ROW_3 = Bytes.toBytes("r3");
103
104  private static final String TESTGROUP_1 = "testgroup_1";
105  private static final String TESTGROUP_2 = "testgroup_2";
106
107  private static User TESTGROUP1_USER1;
108  private static User TESTGROUP2_USER1;
109
110  @Rule
111  public TableNameTestRule testTable = new TableNameTestRule();
112  private String namespace = "testNamespace";
113  private String tname = namespace + ":testtable1";
114  private TableName tableName = TableName.valueOf(tname);
115  private static String TESTGROUP_1_NAME;
116
117  @BeforeClass
118  public static void setupBeforeClass() throws Exception {
119    conf = TEST_UTIL.getConfiguration();
120    // Up the handlers; this test needs more than usual.
121    conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
122    // Enable security
123    enableSecurity(conf);
124    // Verify enableSecurity sets up what we require
125    verifyConfiguration(conf);
126    TEST_UTIL.startMiniCluster();
127    // Wait for the ACL table to become available
128    TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME);
129
130    TESTGROUP_1_NAME = toGroupEntry(TESTGROUP_1);
131    TESTGROUP1_USER1 =
132      User.createUserForTesting(conf, "testgroup1_user1", new String[] { TESTGROUP_1 });
133    TESTGROUP2_USER1 =
134      User.createUserForTesting(conf, "testgroup2_user2", new String[] { TESTGROUP_2 });
135
136    systemUserConnection = ConnectionFactory.createConnection(conf);
137  }
138
139  @Before
140  public void setUp() throws Exception {
141    createNamespace(TEST_UTIL, NamespaceDescriptor.create(namespace).build());
142    try (Table table =
143      createTable(TEST_UTIL, tableName, new byte[][] { TEST_FAMILY, TEST_FAMILY_2 })) {
144      TEST_UTIL.waitTableEnabled(tableName);
145
146      // Ingesting test data.
147      table.put(Arrays.asList(new Put(TEST_ROW).addColumn(TEST_FAMILY, Q1, value1),
148        new Put(TEST_ROW_2).addColumn(TEST_FAMILY, Q2, value2),
149        new Put(TEST_ROW_3).addColumn(TEST_FAMILY_2, Q1, value1)));
150    }
151
152    assertEquals(1, PermissionStorage.getTablePermissions(conf, tableName).size());
153    try {
154      assertEquals(1,
155        AccessControlClient.getUserPermissions(systemUserConnection, tableName.toString()).size());
156    } catch (Throwable e) {
157      LOG.error("Error during call of AccessControlClient.getUserPermissions. ", e);
158    }
159
160  }
161
162  @AfterClass
163  public static void tearDownAfterClass() throws Exception {
164    systemUserConnection.close();
165    TEST_UTIL.shutdownMiniCluster();
166  }
167
168  @After
169  public void tearDown() throws Exception {
170    // Clean the _acl_ table
171    try {
172      deleteTable(TEST_UTIL, tableName);
173    } catch (TableNotFoundException ex) {
174      // Test deleted the table, no problem
175      LOG.info("Test deleted table " + tableName);
176    }
177    deleteNamespace(TEST_UTIL, namespace);
178    // Verify all table/namespace permissions are erased
179    assertEquals(0, PermissionStorage.getTablePermissions(conf, tableName).size());
180    assertEquals(0, PermissionStorage.getNamespacePermissions(conf, namespace).size());
181  }
182
183  @Test
184  public void testCreateWithCorrectOwner() throws Exception {
185    // Create a test user
186    final User testUser =
187      User.createUserForTesting(TEST_UTIL.getConfiguration(), "TestUser", new String[0]);
188    // Grant the test user the ability to create tables
189    SecureTestUtil.grantGlobal(TEST_UTIL, testUser.getShortName(), Action.CREATE);
190    verifyAllowed(new AccessTestAction() {
191      @Override
192      public Object run() throws Exception {
193        TableDescriptor tableDescriptor =
194          TableDescriptorBuilder.newBuilder(testTable.getTableName())
195            .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
196        try (Connection connection =
197          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration(), testUser)) {
198          try (Admin admin = connection.getAdmin()) {
199            createTable(TEST_UTIL, admin, tableDescriptor);
200          }
201        }
202        return null;
203      }
204    }, testUser);
205    TEST_UTIL.waitTableAvailable(testTable.getTableName());
206    // Verify that owner permissions have been granted to the test user on the
207    // table just created
208    List<UserPermission> perms = PermissionStorage
209      .getTablePermissions(conf, testTable.getTableName()).get(testUser.getShortName());
210    assertNotNull(perms);
211    assertFalse(perms.isEmpty());
212    // Should be RWXCA
213    assertTrue(perms.get(0).getPermission().implies(Permission.Action.READ));
214    assertTrue(perms.get(0).getPermission().implies(Permission.Action.WRITE));
215    assertTrue(perms.get(0).getPermission().implies(Permission.Action.EXEC));
216    assertTrue(perms.get(0).getPermission().implies(Permission.Action.CREATE));
217    assertTrue(perms.get(0).getPermission().implies(Permission.Action.ADMIN));
218  }
219
220  @Test
221  public void testCreateTableWithGroupPermissions() throws Exception {
222    grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
223    try {
224      AccessTestAction createAction = new AccessTestAction() {
225        @Override
226        public Object run() throws Exception {
227          TableDescriptor tableDescriptor =
228            TableDescriptorBuilder.newBuilder(testTable.getTableName())
229              .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
230          try (Connection connection =
231            ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
232            try (Admin admin = connection.getAdmin()) {
233              admin.createTable(tableDescriptor);
234            }
235          }
236          return null;
237        }
238      };
239      verifyAllowed(createAction, TESTGROUP1_USER1);
240      verifyDenied(createAction, TESTGROUP2_USER1);
241    } finally {
242      revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
243    }
244  }
245
246  @Test
247  public void testACLTableAccess() throws Exception {
248    final Configuration conf = TEST_UTIL.getConfiguration();
249
250    // Superuser
251    User superUser = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
252
253    // Global users
254    User globalRead = User.createUserForTesting(conf, "globalRead", new String[0]);
255    User globalWrite = User.createUserForTesting(conf, "globalWrite", new String[0]);
256    User globalCreate = User.createUserForTesting(conf, "globalCreate", new String[0]);
257    User globalAdmin = User.createUserForTesting(conf, "globalAdmin", new String[0]);
258    SecureTestUtil.grantGlobal(TEST_UTIL, globalRead.getShortName(), Action.READ);
259    SecureTestUtil.grantGlobal(TEST_UTIL, globalWrite.getShortName(), Action.WRITE);
260    SecureTestUtil.grantGlobal(TEST_UTIL, globalCreate.getShortName(), Action.CREATE);
261    SecureTestUtil.grantGlobal(TEST_UTIL, globalAdmin.getShortName(), Action.ADMIN);
262
263    // Namespace users
264    User nsRead = User.createUserForTesting(conf, "nsRead", new String[0]);
265    User nsWrite = User.createUserForTesting(conf, "nsWrite", new String[0]);
266    User nsCreate = User.createUserForTesting(conf, "nsCreate", new String[0]);
267    User nsAdmin = User.createUserForTesting(conf, "nsAdmin", new String[0]);
268    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsRead.getShortName(),
269      testTable.getTableName().getNamespaceAsString(), Action.READ);
270    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsWrite.getShortName(),
271      testTable.getTableName().getNamespaceAsString(), Action.WRITE);
272    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsCreate.getShortName(),
273      testTable.getTableName().getNamespaceAsString(), Action.CREATE);
274    SecureTestUtil.grantOnNamespace(TEST_UTIL, nsAdmin.getShortName(),
275      testTable.getTableName().getNamespaceAsString(), Action.ADMIN);
276
277    // Table users
278    User tableRead = User.createUserForTesting(conf, "tableRead", new String[0]);
279    User tableWrite = User.createUserForTesting(conf, "tableWrite", new String[0]);
280    User tableCreate = User.createUserForTesting(conf, "tableCreate", new String[0]);
281    User tableAdmin = User.createUserForTesting(conf, "tableAdmin", new String[0]);
282    SecureTestUtil.grantOnTable(TEST_UTIL, tableRead.getShortName(), testTable.getTableName(), null,
283      null, Action.READ);
284    SecureTestUtil.grantOnTable(TEST_UTIL, tableWrite.getShortName(), testTable.getTableName(),
285      null, null, Action.WRITE);
286    SecureTestUtil.grantOnTable(TEST_UTIL, tableCreate.getShortName(), testTable.getTableName(),
287      null, null, Action.CREATE);
288    SecureTestUtil.grantOnTable(TEST_UTIL, tableAdmin.getShortName(), testTable.getTableName(),
289      null, null, Action.ADMIN);
290
291    grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
292    try {
293      // Write tests
294
295      AccessTestAction writeAction = new AccessTestAction() {
296        @Override
297        public Object run() throws Exception {
298
299          try (Connection conn = ConnectionFactory.createConnection(conf);
300            Table t = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
301            t.put(new Put(TEST_ROW).addColumn(PermissionStorage.ACL_LIST_FAMILY, TEST_QUALIFIER,
302              TEST_VALUE));
303            return null;
304          } finally {
305          }
306        }
307      };
308
309      // All writes to ACL table denied except for GLOBAL WRITE permission and superuser
310
311      verifyDenied(writeAction, globalAdmin, globalCreate, globalRead, TESTGROUP2_USER1);
312      verifyDenied(writeAction, nsAdmin, nsCreate, nsRead, nsWrite);
313      verifyDenied(writeAction, tableAdmin, tableCreate, tableRead, tableWrite);
314      verifyAllowed(writeAction, superUser, globalWrite, TESTGROUP1_USER1);
315    } finally {
316      revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
317    }
318
319    grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
320    try {
321      // Read tests
322
323      AccessTestAction scanAction = new AccessTestAction() {
324        @Override
325        public Object run() throws Exception {
326          try (Connection conn = ConnectionFactory.createConnection(conf);
327            Table t = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
328            ResultScanner s = t.getScanner(new Scan());
329            try {
330              for (Result r = s.next(); r != null; r = s.next()) {
331                // do nothing
332              }
333            } finally {
334              s.close();
335            }
336            return null;
337          }
338        }
339      };
340
341      // All reads from ACL table denied except for GLOBAL READ and superuser
342
343      verifyDenied(scanAction, globalAdmin, globalCreate, globalWrite, TESTGROUP2_USER1);
344      verifyDenied(scanAction, nsCreate, nsAdmin, nsRead, nsWrite);
345      verifyDenied(scanAction, tableCreate, tableAdmin, tableRead, tableWrite);
346      verifyAllowed(scanAction, superUser, globalRead, TESTGROUP1_USER1);
347    } finally {
348      revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
349    }
350  }
351
352  /*
353   * Test table scan operation at table, column family and column qualifier level.
354   */
355  @Test
356  public void testPostGrantAndRevokeScanAction() throws Exception {
357    AccessTestAction scanTableActionForGroupWithTableLevelAccess = new AccessTestAction() {
358      @Override
359      public Void run() throws Exception {
360        try (Connection connection = ConnectionFactory.createConnection(conf);
361          Table table = connection.getTable(tableName)) {
362          Scan s1 = new Scan();
363          try (ResultScanner scanner1 = table.getScanner(s1)) {
364            Result[] next1 = scanner1.next(5);
365            assertTrue("User having table level access should be able to scan all "
366              + "the data in the table.", next1.length == 3);
367          }
368        }
369        return null;
370      }
371    };
372
373    AccessTestAction scanTableActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
374      @Override
375      public Void run() throws Exception {
376        try (Connection connection = ConnectionFactory.createConnection(conf);
377          Table table = connection.getTable(tableName)) {
378          Scan s1 = new Scan();
379          try (ResultScanner scanner1 = table.getScanner(s1)) {
380            Result[] next1 = scanner1.next(5);
381            assertTrue("User having column family level access should be able to scan all "
382              + "the data belonging to that family.", next1.length == 2);
383          }
384        }
385        return null;
386      }
387    };
388
389    AccessTestAction scanFamilyActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
390      @Override
391      public Void run() throws Exception {
392        try (Connection connection = ConnectionFactory.createConnection(conf);
393          Table table = connection.getTable(tableName)) {
394          Scan s1 = new Scan();
395          s1.addFamily(TEST_FAMILY_2);
396          try (ResultScanner scanner1 = table.getScanner(s1)) {
397            scanner1.next();
398          }
399        }
400        return null;
401      }
402    };
403
404    AccessTestAction scanTableActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
405      @Override
406      public Void run() throws Exception {
407        try (Connection connection = ConnectionFactory.createConnection(conf);
408          Table table = connection.getTable(tableName)) {
409          Scan s1 = new Scan();
410          try (ResultScanner scanner1 = table.getScanner(s1)) {
411            Result[] next1 = scanner1.next(5);
412            assertTrue("User having column qualifier level access should be able to scan "
413              + "that column family qualifier data.", next1.length == 1);
414          }
415        }
416        return null;
417      }
418    };
419
420    AccessTestAction scanFamilyActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
421      @Override
422      public Void run() throws Exception {
423        try (Connection connection = ConnectionFactory.createConnection(conf);
424          Table table = connection.getTable(tableName)) {
425          Scan s1 = new Scan();
426          s1.addFamily(TEST_FAMILY_2);
427          try (ResultScanner scanner1 = table.getScanner(s1)) {
428            scanner1.next();
429          }
430        }
431        return null;
432      }
433    };
434
435    AccessTestAction scanQualifierActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
436      @Override
437      public Void run() throws Exception {
438        try (Connection connection = ConnectionFactory.createConnection(conf);
439          Table table = connection.getTable(tableName)) {
440          Scan s1 = new Scan();
441          s1.addColumn(TEST_FAMILY, Q2);
442          try (ResultScanner scanner1 = table.getScanner(s1)) {
443            scanner1.next();
444          }
445        }
446        return null;
447      }
448    };
449
450    // Verify user from a group which has table level access can read all the data and group which
451    // has no access can't read any data.
452    grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null, Action.READ);
453    verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
454    verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithTableLevelAccess);
455
456    // Verify user from a group whose table level access has been revoked can't read any data.
457    revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null);
458    verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
459
460    // Verify user from a group which has column family level access can read all the data
461    // belonging to that family and group which has no access can't read any data.
462    grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null, Permission.Action.READ);
463    verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
464    verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
465    verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithFamilyLevelAccess);
466    verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
467
468    // Verify user from a group whose column family level access has been revoked can't read any
469    // data from that family.
470    revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null);
471    verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
472
473    // Verify user from a group which has column qualifier level access can read data that has this
474    // family and qualifier, and group which has no access can't read any data.
475    grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1, Action.READ);
476    verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
477    verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
478    verifyDenied(TESTGROUP1_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
479    verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithQualifierLevelAccess);
480    verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
481    verifyDenied(TESTGROUP2_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
482
483    // Verify user from a group whose column qualifier level access has been revoked can't read the
484    // data having this column family and qualifier.
485    revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1);
486    verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
487  }
488
489  public static class MyAccessController extends AccessController {
490  }
491
492  @Test
493  public void testCoprocessorLoading() throws Exception {
494    MasterCoprocessorHost cpHost =
495      TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
496    cpHost.load(MyAccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
497    AccessController ACCESS_CONTROLLER = cpHost.findCoprocessor(MyAccessController.class);
498    MasterCoprocessorEnvironment CP_ENV =
499      cpHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
500    RegionServerCoprocessorHost rsHost =
501      TEST_UTIL.getMiniHBaseCluster().getRegionServer(0).getRegionServerCoprocessorHost();
502    RegionServerCoprocessorEnvironment RSCP_ENV =
503      rsHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
504  }
505
506  @Test
507  public void testACLZNodeDeletion() throws Exception {
508    String baseAclZNode = "/hbase/acl/";
509    String ns = "testACLZNodeDeletionNamespace";
510    NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
511    createNamespace(TEST_UTIL, desc);
512
513    final TableName table = TableName.valueOf(ns, "testACLZNodeDeletionTable");
514    final byte[] family = Bytes.toBytes("f1");
515    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(table)
516      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build();
517    createTable(TEST_UTIL, tableDescriptor);
518
519    // Namespace needs this, as they follow the lazy creation of ACL znode.
520    grantOnNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
521    ZKWatcher zkw = TEST_UTIL.getMiniHBaseCluster().getMaster().getZooKeeper();
522    assertTrue("The acl znode for table should exist",
523      ZKUtil.checkExists(zkw, baseAclZNode + table.getNameAsString()) != -1);
524    assertTrue("The acl znode for namespace should exist",
525      ZKUtil.checkExists(zkw, baseAclZNode + convertToNamespace(ns)) != -1);
526
527    revokeFromNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
528    deleteTable(TEST_UTIL, table);
529    deleteNamespace(TEST_UTIL, ns);
530
531    assertTrue("The acl znode for table should have been deleted",
532      ZKUtil.checkExists(zkw, baseAclZNode + table.getNameAsString()) == -1);
533    assertTrue("The acl znode for namespace should have been deleted",
534      ZKUtil.checkExists(zkw, baseAclZNode + convertToNamespace(ns)) == -1);
535  }
536}