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