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