View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.security.access;
19  
20  import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertTrue;
25  import java.util.Arrays;
26  import java.util.List;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.Coprocessor;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.HTableDescriptor;
36  import org.apache.hadoop.hbase.NamespaceDescriptor;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.TableNameTestRule;
39  import org.apache.hadoop.hbase.TableNotFoundException;
40  import org.apache.hadoop.hbase.client.Admin;
41  import org.apache.hadoop.hbase.client.Connection;
42  import org.apache.hadoop.hbase.client.ConnectionFactory;
43  import org.apache.hadoop.hbase.client.Put;
44  import org.apache.hadoop.hbase.client.Result;
45  import org.apache.hadoop.hbase.client.ResultScanner;
46  import org.apache.hadoop.hbase.client.Scan;
47  import org.apache.hadoop.hbase.client.Table;
48  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
49  import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
50  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
51  import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
52  import org.apache.hadoop.hbase.security.User;
53  import org.apache.hadoop.hbase.security.access.Permission.Action;
54  import org.apache.hadoop.hbase.testclassification.LargeTests;
55  import org.apache.hadoop.hbase.util.Bytes;
56  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
57  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
58  import org.junit.After;
59  import org.junit.AfterClass;
60  import org.junit.Before;
61  import org.junit.BeforeClass;
62  import org.junit.Rule;
63  import org.junit.Test;
64  import org.junit.experimental.categories.Category;
65  
66  @Category(LargeTests.class)
67  public class TestAccessController2 extends SecureTestUtil {
68    private static final Log LOG = LogFactory.getLog(TestAccessController2.class);
69  
70    private static final byte[] TEST_ROW = Bytes.toBytes("test");
71    private static final byte[] TEST_FAMILY = Bytes.toBytes("f");
72    private static final byte[] TEST_QUALIFIER = Bytes.toBytes("q");
73    private static final byte[] TEST_VALUE = Bytes.toBytes("value");
74  
75    private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
76    private static Configuration conf;
77  
78    /** The systemUserConnection created here is tied to the system user. In case, you are planning
79     * to create AccessTestAction, DON'T use this systemUserConnection as the 'doAs' user
80     * gets  eclipsed by the system user. */
81    private static Connection systemUserConnection;
82  
83    private final static byte[] Q1 = Bytes.toBytes("q1");
84    private final static byte[] value1 = Bytes.toBytes("value1");
85  
86    private static byte[] TEST_FAMILY_2 = Bytes.toBytes("f2");
87    private static byte[] TEST_ROW_2 = Bytes.toBytes("r2");
88    private final static byte[] Q2 = Bytes.toBytes("q2");
89    private final static byte[] value2 = Bytes.toBytes("value2");
90  
91    private static byte[] TEST_ROW_3 = Bytes.toBytes("r3");
92  
93    private static final String TESTGROUP_1 = "testgroup_1";
94    private static final String TESTGROUP_2 = "testgroup_2";
95  
96    private static User TESTGROUP1_USER1;
97    private static User TESTGROUP2_USER1;
98  
99    @Rule
100   public TableNameTestRule testTable = new TableNameTestRule();
101   private String namespace = "testNamespace";
102   private String tname = namespace + ":testtable1";
103   private TableName tableName = TableName.valueOf(tname);
104   private static String TESTGROUP_1_NAME;
105 
106   @BeforeClass
107   public static void setupBeforeClass() throws Exception {
108     conf = TEST_UTIL.getConfiguration();
109     // Up the handlers; this test needs more than usual.
110     conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
111     // Enable security
112     enableSecurity(conf);
113     // Verify enableSecurity sets up what we require
114     verifyConfiguration(conf);
115     TEST_UTIL.startMiniCluster();
116     // Wait for the ACL table to become available
117     TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
118 
119     TESTGROUP_1_NAME = toGroupEntry(TESTGROUP_1);
120     TESTGROUP1_USER1 =
121         User.createUserForTesting(conf, "testgroup1_user1", new String[] { TESTGROUP_1 });
122     TESTGROUP2_USER1 =
123         User.createUserForTesting(conf, "testgroup2_user2", new String[] { TESTGROUP_2 });
124 
125     systemUserConnection = ConnectionFactory.createConnection(conf);
126   }
127 
128   @Before
129   public void setUp() throws Exception {
130     createNamespace(TEST_UTIL, NamespaceDescriptor.create(namespace).build());
131     try (Table table = createTable(TEST_UTIL, tableName,
132           new byte[][] { TEST_FAMILY, TEST_FAMILY_2 })) {
133       TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
134 
135       // Ingesting test data.
136       table.put(Arrays.asList(new Put(TEST_ROW).addColumn(TEST_FAMILY, Q1, value1),
137           new Put(TEST_ROW_2).addColumn(TEST_FAMILY, Q2, value2),
138           new Put(TEST_ROW_3).addColumn(TEST_FAMILY_2, Q1, value1)));
139     }
140 
141     assertEquals(1, AccessControlLists.getTablePermissions(conf, tableName).size());
142     try {
143       assertEquals(1, AccessControlClient.getUserPermissions(systemUserConnection, tableName.toString())
144           .size());
145     } catch (Throwable e) {
146       LOG.error("Error during call of AccessControlClient.getUserPermissions. ", e);
147     }
148   }
149 
150   @AfterClass
151   public static void tearDownAfterClass() throws Exception {
152     systemUserConnection.close();
153     TEST_UTIL.shutdownMiniCluster();
154   }
155 
156   @After
157   public void tearDown() throws Exception {
158     // Clean the _acl_ table
159     try {
160       deleteTable(TEST_UTIL, tableName);
161     } catch (TableNotFoundException ex) {
162       // Test deleted the table, no problem
163       LOG.info("Test deleted table " + tableName);
164     }
165     deleteNamespace(TEST_UTIL, namespace);
166     // Verify all table/namespace permissions are erased
167     assertEquals(0, AccessControlLists.getTablePermissions(conf, tableName).size());
168     assertEquals(0, AccessControlLists.getNamespacePermissions(conf, namespace).size());
169   }
170 
171   @Test (timeout=180000)
172   public void testCreateWithCorrectOwner() throws Exception {
173     // Create a test user
174     final User testUser = User.createUserForTesting(TEST_UTIL.getConfiguration(), "TestUser",
175       new String[0]);
176     // Grant the test user the ability to create tables
177     SecureTestUtil.grantGlobal(TEST_UTIL, testUser.getShortName(), Action.CREATE);
178     verifyAllowed(new AccessTestAction() {
179       @Override
180       public Object run() throws Exception {
181         HTableDescriptor desc = new HTableDescriptor(testTable.getTableName());
182         desc.addFamily(new HColumnDescriptor(TEST_FAMILY));
183         try (Connection connection =
184             ConnectionFactory.createConnection(TEST_UTIL.getConfiguration(), testUser)) {
185           try (Admin admin = connection.getAdmin()) {
186             createTable(TEST_UTIL, admin, desc);
187           }
188         }
189         return null;
190       }
191     }, testUser);
192     TEST_UTIL.waitTableAvailable(testTable.getTableName());
193     // Verify that owner permissions have been granted to the test user on the
194     // table just created
195     List<TablePermission> perms =
196       AccessControlLists.getTablePermissions(conf, testTable.getTableName())
197        .get(testUser.getShortName());
198     assertNotNull(perms);
199     assertFalse(perms.isEmpty());
200     // Should be RWXCA
201     assertTrue(perms.get(0).implies(Permission.Action.READ));
202     assertTrue(perms.get(0).implies(Permission.Action.WRITE));
203     assertTrue(perms.get(0).implies(Permission.Action.EXEC));
204     assertTrue(perms.get(0).implies(Permission.Action.CREATE));
205     assertTrue(perms.get(0).implies(Permission.Action.ADMIN));
206   }
207 
208   @Test (timeout=180000)
209   public void testCreateTableWithGroupPermissions() throws Exception {
210     grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
211     try {
212       AccessTestAction createAction = new AccessTestAction() {
213         @Override
214         public Object run() throws Exception {
215           HTableDescriptor desc = new HTableDescriptor(testTable.getTableName());
216           desc.addFamily(new HColumnDescriptor(TEST_FAMILY));
217           try (Connection connection =
218               ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
219             try (Admin admin = connection.getAdmin()) {
220               admin.createTable(desc);
221             }
222           }
223           return null;
224         }
225       };
226       verifyAllowed(createAction, TESTGROUP1_USER1);
227       verifyDenied(createAction, TESTGROUP2_USER1);
228     } finally {
229       revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
230     }
231   }
232 
233   @Test (timeout=180000)
234   public void testACLTableAccess() throws Exception {
235     final Configuration conf = TEST_UTIL.getConfiguration();
236 
237     // Superuser
238     User superUser = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
239 
240     // Global users
241     User globalRead = User.createUserForTesting(conf, "globalRead", new String[0]);
242     User globalWrite = User.createUserForTesting(conf, "globalWrite", new String[0]);
243     User globalCreate = User.createUserForTesting(conf, "globalCreate", new String[0]);
244     User globalAdmin = User.createUserForTesting(conf, "globalAdmin", new String[0]);
245     SecureTestUtil.grantGlobal(TEST_UTIL, globalRead.getShortName(), Action.READ);
246     SecureTestUtil.grantGlobal(TEST_UTIL, globalWrite.getShortName(), Action.WRITE);
247     SecureTestUtil.grantGlobal(TEST_UTIL, globalCreate.getShortName(), Action.CREATE);
248     SecureTestUtil.grantGlobal(TEST_UTIL, globalAdmin.getShortName(), Action.ADMIN);
249 
250     // Namespace users
251     User nsRead = User.createUserForTesting(conf, "nsRead", new String[0]);
252     User nsWrite = User.createUserForTesting(conf, "nsWrite", new String[0]);
253     User nsCreate = User.createUserForTesting(conf, "nsCreate", new String[0]);
254     User nsAdmin = User.createUserForTesting(conf, "nsAdmin", new String[0]);
255     SecureTestUtil.grantOnNamespace(TEST_UTIL, nsRead.getShortName(),
256       testTable.getTableName().getNamespaceAsString(), Action.READ);
257     SecureTestUtil.grantOnNamespace(TEST_UTIL, nsWrite.getShortName(),
258       testTable.getTableName().getNamespaceAsString(), Action.WRITE);
259     SecureTestUtil.grantOnNamespace(TEST_UTIL, nsCreate.getShortName(),
260       testTable.getTableName().getNamespaceAsString(), Action.CREATE);
261     SecureTestUtil.grantOnNamespace(TEST_UTIL, nsAdmin.getShortName(),
262       testTable.getTableName().getNamespaceAsString(), Action.ADMIN);
263 
264     // Table users
265     User tableRead = User.createUserForTesting(conf, "tableRead", new String[0]);
266     User tableWrite = User.createUserForTesting(conf, "tableWrite", new String[0]);
267     User tableCreate = User.createUserForTesting(conf, "tableCreate", new String[0]);
268     User tableAdmin = User.createUserForTesting(conf, "tableAdmin", new String[0]);
269     SecureTestUtil.grantOnTable(TEST_UTIL, tableRead.getShortName(),
270       testTable.getTableName(), null, null, Action.READ);
271     SecureTestUtil.grantOnTable(TEST_UTIL, tableWrite.getShortName(),
272       testTable.getTableName(), null, null, Action.WRITE);
273     SecureTestUtil.grantOnTable(TEST_UTIL, tableCreate.getShortName(),
274       testTable.getTableName(), null, null, Action.CREATE);
275     SecureTestUtil.grantOnTable(TEST_UTIL, tableAdmin.getShortName(),
276       testTable.getTableName(), null, null, Action.ADMIN);
277 
278     grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
279     try {
280       // Write tests
281 
282       AccessTestAction writeAction = new AccessTestAction() {
283         @Override
284         public Object run() throws Exception {
285           try (Connection conn = ConnectionFactory.createConnection(conf);
286               Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
287             t.put(new Put(TEST_ROW).addColumn(AccessControlLists.ACL_LIST_FAMILY, TEST_QUALIFIER,
288               TEST_VALUE));
289             return null;
290           } finally {
291           }
292         }
293       };
294 
295       // All writes to ACL table denied except for GLOBAL WRITE permission and superuser
296 
297       verifyDenied(writeAction, globalAdmin, globalCreate, globalRead, TESTGROUP2_USER1);
298       verifyDenied(writeAction, nsAdmin, nsCreate, nsRead, nsWrite);
299       verifyDenied(writeAction, tableAdmin, tableCreate, tableRead, tableWrite);
300       verifyAllowed(writeAction, superUser, globalWrite, TESTGROUP1_USER1);
301     } finally {
302       revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
303     }
304 
305     grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
306     try {
307       // Read tests
308 
309       AccessTestAction scanAction = new AccessTestAction() {
310         @Override
311         public Object run() throws Exception {
312           try (Connection conn = ConnectionFactory.createConnection(conf);
313               Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
314             ResultScanner s = t.getScanner(new Scan());
315             try {
316               for (Result r = s.next(); r != null; r = s.next()) {
317                 // do nothing
318               }
319             } finally {
320               s.close();
321             }
322             return null;
323           }
324         }
325       };
326 
327       // All reads from ACL table denied except for GLOBAL READ and superuser
328 
329       verifyDenied(scanAction, globalAdmin, globalCreate, globalWrite, TESTGROUP2_USER1);
330       verifyDenied(scanAction, nsCreate, nsAdmin, nsRead, nsWrite);
331       verifyDenied(scanAction, tableCreate, tableAdmin, tableRead, tableWrite);
332       verifyAllowed(scanAction, superUser, globalRead, TESTGROUP1_USER1);
333     } finally {
334       revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
335     }
336   }
337 
338   /*
339    * Test table scan operation at table, column family and column qualifier level.
340    */
341   @Test(timeout = 300000)
342   public void testPostGrantAndRevokeScanAction() throws Exception {
343     AccessTestAction scanTableActionForGroupWithTableLevelAccess = new AccessTestAction() {
344       @Override
345       public Void run() throws Exception {
346         try (Connection connection = ConnectionFactory.createConnection(conf);
347             Table table = connection.getTable(tableName);) {
348           Scan s1 = new Scan();
349           try (ResultScanner scanner1 = table.getScanner(s1);) {
350             Result[] next1 = scanner1.next(5);
351             assertTrue("User having table level access should be able to scan all "
352                 + "the data in the table.", next1.length == 3);
353           }
354         }
355         return null;
356       }
357     };
358 
359     AccessTestAction scanTableActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
360       @Override
361       public Void run() throws Exception {
362         try (Connection connection = ConnectionFactory.createConnection(conf);
363             Table table = connection.getTable(tableName);) {
364           Scan s1 = new Scan();
365           try (ResultScanner scanner1 = table.getScanner(s1);) {
366             Result[] next1 = scanner1.next(5);
367             assertTrue("User having column family level access should be able to scan all "
368                 + "the data belonging to that family.", next1.length == 2);
369           }
370         }
371         return null;
372       }
373     };
374 
375     AccessTestAction scanFamilyActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
376       @Override
377       public Void run() throws Exception {
378         try (Connection connection = ConnectionFactory.createConnection(conf);
379             Table table = connection.getTable(tableName);) {
380           Scan s1 = new Scan();
381           s1.addFamily(TEST_FAMILY_2);
382           try (ResultScanner scanner1 = table.getScanner(s1);) {
383             scanner1.next();
384           }
385         }
386         return null;
387       }
388     };
389 
390     AccessTestAction scanTableActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
391       @Override
392       public Void run() throws Exception {
393         try (Connection connection = ConnectionFactory.createConnection(conf);
394             Table table = connection.getTable(tableName);) {
395           Scan s1 = new Scan();
396           try (ResultScanner scanner1 = table.getScanner(s1);) {
397             Result[] next1 = scanner1.next(5);
398             assertTrue("User having column qualifier level access should be able to scan "
399                 + "that column family qualifier data.", next1.length == 1);
400           }
401         }
402         return null;
403       }
404     };
405 
406     AccessTestAction scanFamilyActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
407       @Override
408       public Void run() throws Exception {
409         try (Connection connection = ConnectionFactory.createConnection(conf);
410             Table table = connection.getTable(tableName);) {
411           Scan s1 = new Scan();
412           s1.addFamily(TEST_FAMILY_2);
413           try (ResultScanner scanner1 = table.getScanner(s1);) {
414             scanner1.next();
415           }
416         }
417         return null;
418       }
419     };
420 
421     AccessTestAction scanQualifierActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
422       @Override
423       public Void run() throws Exception {
424         try (Connection connection = ConnectionFactory.createConnection(conf);
425             Table table = connection.getTable(tableName);) {
426           Scan s1 = new Scan();
427           s1.addColumn(TEST_FAMILY, Q2);
428           try (ResultScanner scanner1 = table.getScanner(s1);) {
429             scanner1.next();
430           }
431         }
432         return null;
433       }
434     };
435 
436     // Verify user from a group which has table level access can read all the data and group which
437     // has no access can't read any data.
438     grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null, Action.READ);
439     verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
440     verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithTableLevelAccess);
441 
442     // Verify user from a group whose table level access has been revoked can't read any data.
443     revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null);
444     verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
445 
446     // Verify user from a group which has column family level access can read all the data
447     // belonging to that family and group which has no access can't read any data.
448     grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null,
449       Permission.Action.READ);
450     verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
451     verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
452     verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithFamilyLevelAccess);
453     verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
454 
455     // Verify user from a group whose column family level access has been revoked can't read any
456     // data from that family.
457     revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null);
458     verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
459 
460     // Verify user from a group which has column qualifier level access can read data that has this
461     // family and qualifier, and group which has no access can't read any data.
462     grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1, Action.READ);
463     verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
464     verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
465     verifyDenied(TESTGROUP1_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
466     verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithQualifierLevelAccess);
467     verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
468     verifyDenied(TESTGROUP2_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
469 
470     // Verify user from a group whose column qualifier level access has been revoked can't read the
471     // data having this column family and qualifier.
472     revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1);
473     verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
474   }
475 
476   public static class MyAccessController extends AccessController {
477   }
478 
479   @Test (timeout=180000)
480   public void testCoprocessorLoading() throws Exception {
481     MasterCoprocessorHost cpHost =
482         TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
483     cpHost.load(MyAccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
484     AccessController ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(
485       MyAccessController.class.getName());
486     MasterCoprocessorEnvironment CP_ENV = cpHost.createEnvironment(
487       MyAccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
488     RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
489         .getRegionServerCoprocessorHost();
490     RegionServerCoprocessorEnvironment RSCP_ENV = rsHost.createEnvironment(
491       MyAccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
492   }
493 
494   @Test (timeout=180000)
495   public void testACLZNodeDeletion() throws Exception {
496     String baseAclZNode = "/hbase/acl/";
497     String ns = "testACLZNodeDeletionNamespace";
498     NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
499     createNamespace(TEST_UTIL, desc);
500 
501     final TableName table = TableName.valueOf(ns, "testACLZNodeDeletionTable");
502     final byte[] family = Bytes.toBytes("f1");
503     HTableDescriptor htd = new HTableDescriptor(table);
504     htd.addFamily(new HColumnDescriptor(family));
505     createTable(TEST_UTIL, htd);
506     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
507 
508     // Namespace needs this, as they follow the lazy creation of ACL znode.
509     grantOnNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
510     ZooKeeperWatcher zkw = TEST_UTIL.getMiniHBaseCluster().getMaster().getZooKeeper();
511     assertTrue("The acl znode for table should exist",  ZKUtil.checkExists(zkw, baseAclZNode +
512         table.getNameAsString()) != -1);
513     assertTrue("The acl znode for namespace should exist", ZKUtil.checkExists(zkw, baseAclZNode +
514         convertToNamespace(ns)) != -1);
515 
516     revokeFromNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
517     deleteTable(TEST_UTIL, table);
518     deleteNamespace(TEST_UTIL, ns);
519 
520     assertTrue("The acl znode for table should have been deleted",
521         ZKUtil.checkExists(zkw, baseAclZNode + table.getNameAsString()) == -1);
522     assertTrue( "The acl znode for namespace should have been deleted",
523         ZKUtil.checkExists(zkw, baseAclZNode + convertToNamespace(ns)) == -1);
524   }
525 }