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