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  
19  package org.apache.hadoop.hbase.security.access;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.IOException;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.NavigableMap;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.fs.FileStatus;
35  import org.apache.hadoop.fs.FileSystem;
36  import org.apache.hadoop.fs.Path;
37  import org.apache.hadoop.fs.permission.FsPermission;
38  import org.apache.hadoop.hbase.Coprocessor;
39  import org.apache.hadoop.hbase.CoprocessorEnvironment;
40  import org.apache.hadoop.hbase.HBaseIOException;
41  import org.apache.hadoop.hbase.HBaseTestingUtility;
42  import org.apache.hadoop.hbase.HColumnDescriptor;
43  import org.apache.hadoop.hbase.HConstants;
44  import org.apache.hadoop.hbase.HRegionInfo;
45  import org.apache.hadoop.hbase.HTableDescriptor;
46  import org.apache.hadoop.hbase.KeyValue;
47  import org.apache.hadoop.hbase.testclassification.LargeTests;
48  import org.apache.hadoop.hbase.MiniHBaseCluster;
49  import org.apache.hadoop.hbase.NamespaceDescriptor;
50  import org.apache.hadoop.hbase.ServerName;
51  import org.apache.hadoop.hbase.TableName;
52  import org.apache.hadoop.hbase.TableNotFoundException;
53  import org.apache.hadoop.hbase.Tag;
54  import org.apache.hadoop.hbase.client.Append;
55  import org.apache.hadoop.hbase.client.Delete;
56  import org.apache.hadoop.hbase.client.Get;
57  import org.apache.hadoop.hbase.client.HBaseAdmin;
58  import org.apache.hadoop.hbase.client.HTable;
59  import org.apache.hadoop.hbase.client.Increment;
60  import org.apache.hadoop.hbase.client.Put;
61  import org.apache.hadoop.hbase.client.Result;
62  import org.apache.hadoop.hbase.client.ResultScanner;
63  import org.apache.hadoop.hbase.client.Scan;
64  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
65  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
66  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
67  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
68  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
69  import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
70  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.CountRequest;
71  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.CountResponse;
72  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.HelloRequest;
73  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.HelloResponse;
74  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.IncrementCountRequest;
75  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.IncrementCountResponse;
76  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.NoopRequest;
77  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.NoopResponse;
78  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingRequest;
79  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingResponse;
80  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingService;
81  import org.apache.hadoop.hbase.exceptions.HBaseException;
82  import org.apache.hadoop.hbase.io.hfile.CacheConfig;
83  import org.apache.hadoop.hbase.io.hfile.HFile;
84  import org.apache.hadoop.hbase.io.hfile.HFileContext;
85  import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
86  import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
87  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
88  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
89  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
90  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
91  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
92  import org.apache.hadoop.hbase.regionserver.HRegion;
93  import org.apache.hadoop.hbase.regionserver.HRegionServer;
94  import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
95  import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
96  import org.apache.hadoop.hbase.regionserver.ScanType;
97  import org.apache.hadoop.hbase.security.User;
98  import org.apache.hadoop.hbase.security.access.Permission.Action;
99  import org.apache.hadoop.hbase.util.Bytes;
100 import org.apache.hadoop.hbase.util.JVMClusterUtil;
101 import org.apache.hadoop.hbase.util.TestTableName;
102 import org.apache.log4j.Level;
103 import org.apache.log4j.Logger;
104 import org.junit.After;
105 import org.junit.AfterClass;
106 import org.junit.Before;
107 import org.junit.BeforeClass;
108 import org.junit.Rule;
109 import org.junit.Test;
110 import org.junit.experimental.categories.Category;
111 
112 import com.google.protobuf.BlockingRpcChannel;
113 import com.google.protobuf.RpcCallback;
114 import com.google.protobuf.RpcController;
115 import com.google.protobuf.Service;
116 import com.google.protobuf.ServiceException;
117 
118 /**
119  * Performs authorization checks for common operations, according to different
120  * levels of authorized users.
121  */
122 @Category(LargeTests.class)
123 public class TestAccessController extends SecureTestUtil {
124   private static final Log LOG = LogFactory.getLog(TestAccessController.class);
125 
126   static {
127     Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
128     Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
129     Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
130   }
131 
132   @Rule public TestTableName TEST_TABLE = new TestTableName();
133   private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
134   private static Configuration conf;
135 
136   // user with all permissions
137   private static User SUPERUSER;
138   // user granted with all global permission
139   private static User USER_ADMIN;
140   // user with rw permissions on column family.
141   private static User USER_RW;
142   // user with read-only permissions
143   private static User USER_RO;
144   // user is table owner. will have all permissions on table
145   private static User USER_OWNER;
146   // user with create table permissions alone
147   private static User USER_CREATE;
148   // user with no permissions
149   private static User USER_NONE;
150   // user with admin rights on the column family
151   private static User USER_ADMIN_CF;
152 
153   // TODO: convert this test to cover the full matrix in
154   // https://hbase.apache.org/book/appendix_acl_matrix.html
155   // creating all Scope x Permission combinations
156 
157   private static TableName TEST_TABLE2 = TableName.valueOf("testtable2");
158   private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
159   private static byte[] TEST_QUALIFIER = Bytes.toBytes("q1");
160   private static byte[] TEST_ROW = Bytes.toBytes("r1");
161 
162   private static MasterCoprocessorEnvironment CP_ENV;
163   private static AccessController ACCESS_CONTROLLER;
164   private static RegionServerCoprocessorEnvironment RSCP_ENV;
165   private RegionCoprocessorEnvironment RCP_ENV;
166 
167   @BeforeClass
168   public static void setupBeforeClass() throws Exception {
169     // setup configuration
170     conf = TEST_UTIL.getConfiguration();
171     conf.set("hbase.master.hfilecleaner.plugins",
172       "org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner," +
173       "org.apache.hadoop.hbase.master.snapshot.SnapshotHFileCleaner");
174     conf.set("hbase.master.logcleaner.plugins",
175       "org.apache.hadoop.hbase.master.snapshot.SnapshotLogCleaner");
176     // Enable security
177     enableSecurity(conf);
178     // In this particular test case, we can't use SecureBulkLoadEndpoint because its doAs will fail
179     // to move a file for a random user
180     conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
181     // Verify enableSecurity sets up what we require
182     verifyConfiguration(conf);
183 
184     // Enable EXEC permission checking
185     conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true);
186 
187     TEST_UTIL.startMiniCluster();
188     MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster().getCoprocessorHost();
189     cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
190     ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(AccessController.class.getName());
191     CP_ENV = cpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
192       Coprocessor.PRIORITY_HIGHEST, 1, conf);
193     RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
194         .getCoprocessorHost();
195     RSCP_ENV = rsHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
196       Coprocessor.PRIORITY_HIGHEST, 1, conf);
197 
198     // Wait for the ACL table to become available
199     TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
200 
201     // create a set of test users
202     SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
203     USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
204     USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
205     USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
206     USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
207     USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
208     USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
209     USER_ADMIN_CF = User.createUserForTesting(conf, "col_family_admin", new String[0]);
210   }
211 
212   @AfterClass
213   public static void tearDownAfterClass() throws Exception {
214     TEST_UTIL.shutdownMiniCluster();
215   }
216 
217   @Before
218   public void setUp() throws Exception {
219     // Create the test table (owner added to the _acl_ table)
220     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
221     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
222     HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
223     hcd.setMaxVersions(100);
224     htd.addFamily(hcd);
225     htd.setOwner(USER_OWNER);
226     admin.createTable(htd, new byte[][] { Bytes.toBytes("s") });
227     TEST_UTIL.waitTableEnabled(TEST_TABLE.getTableName().getName());
228 
229     HRegion region = TEST_UTIL.getHBaseCluster().getRegions(TEST_TABLE.getTableName()).get(0);
230     RegionCoprocessorHost rcpHost = region.getCoprocessorHost();
231     RCP_ENV = rcpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
232       Coprocessor.PRIORITY_HIGHEST, 1, conf);
233 
234     // Set up initial grants
235 
236     grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(),
237       Permission.Action.ADMIN,
238       Permission.Action.CREATE,
239       Permission.Action.READ,
240       Permission.Action.WRITE);
241 
242     grantOnTable(TEST_UTIL, USER_RW.getShortName(),
243       TEST_TABLE.getTableName(), TEST_FAMILY, null,
244       Permission.Action.READ,
245       Permission.Action.WRITE);
246 
247     // USER_CREATE is USER_RW plus CREATE permissions
248     grantOnTable(TEST_UTIL, USER_CREATE.getShortName(),
249       TEST_TABLE.getTableName(), null, null,
250       Permission.Action.CREATE,
251       Permission.Action.READ,
252       Permission.Action.WRITE);
253 
254     grantOnTable(TEST_UTIL, USER_RO.getShortName(),
255       TEST_TABLE.getTableName(), TEST_FAMILY, null,
256       Permission.Action.READ);
257 
258     grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(),
259       TEST_TABLE.getTableName(), TEST_FAMILY,
260       null, Permission.Action.ADMIN, Permission.Action.CREATE);
261 
262     assertEquals(5, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
263     try {
264       assertEquals(5, AccessControlClient.getUserPermissions(conf, TEST_TABLE.toString()).size());
265     } catch (Throwable e) {
266       LOG.error("error during call of AccessControlClient.getUserPermissions. " + e.getStackTrace());
267     }
268   }
269 
270   @After
271   public void tearDown() throws Exception {
272     // Clean the _acl_ table
273     try {
274       TEST_UTIL.deleteTable(TEST_TABLE.getTableName());
275     } catch (TableNotFoundException ex) {
276       // Test deleted the table, no problem
277       LOG.info("Test deleted table " + TEST_TABLE.getTableName());
278     }
279     assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
280   }
281 
282   @Test
283   public void testTableCreate() throws Exception {
284     AccessTestAction createTable = new AccessTestAction() {
285       @Override
286       public Object run() throws Exception {
287         HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testnewtable"));
288         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
289         ACCESS_CONTROLLER.preCreateTable(ObserverContext.createAndPrepare(CP_ENV, null), htd, null);
290         return null;
291       }
292     };
293 
294     // verify that superuser can create tables
295     verifyAllowed(createTable, SUPERUSER, USER_ADMIN);
296 
297     // all others should be denied
298     verifyDenied(createTable, USER_CREATE, USER_RW, USER_RO, USER_NONE);
299   }
300 
301   @Test
302   public void testTableModify() throws Exception {
303     AccessTestAction modifyTable = new AccessTestAction() {
304       @Override
305       public Object run() throws Exception {
306         HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
307         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
308         htd.addFamily(new HColumnDescriptor("fam_" + User.getCurrent().getShortName()));
309         ACCESS_CONTROLLER.preModifyTable(ObserverContext.createAndPrepare(CP_ENV, null),
310           TEST_TABLE.getTableName(), htd);
311         return null;
312       }
313     };
314 
315     verifyAllowed(modifyTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
316     verifyDenied(modifyTable, USER_RW, USER_RO, USER_NONE);
317   }
318 
319   @Test
320   public void testTableDelete() throws Exception {
321     AccessTestAction deleteTable = new AccessTestAction() {
322       @Override
323       public Object run() throws Exception {
324         ACCESS_CONTROLLER
325             .preDeleteTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName());
326         return null;
327       }
328     };
329 
330     verifyAllowed(deleteTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
331     verifyDenied(deleteTable, USER_RW, USER_RO, USER_NONE);
332   }
333 
334   @Test
335   public void testTableTruncate() throws Exception {
336     AccessTestAction truncateTable = new AccessTestAction() {
337       @Override
338       public Object run() throws Exception {
339         ACCESS_CONTROLLER
340             .preTruncateTable(ObserverContext.createAndPrepare(CP_ENV, null),
341               TEST_TABLE.getTableName());
342         return null;
343       }
344     };
345 
346     verifyAllowed(truncateTable, SUPERUSER, USER_ADMIN, USER_CREATE);
347     verifyDenied(truncateTable, USER_RW, USER_RO, USER_NONE, USER_OWNER);
348   }
349 
350   @Test
351   public void testAddColumn() throws Exception {
352     final HColumnDescriptor hcd = new HColumnDescriptor("fam_new");
353     AccessTestAction action = new AccessTestAction() {
354       @Override
355       public Object run() throws Exception {
356         ACCESS_CONTROLLER.preAddColumn(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(),
357           hcd);
358         return null;
359       }
360     };
361 
362     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
363     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
364   }
365 
366   @Test
367   public void testModifyColumn() throws Exception {
368     final HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
369     hcd.setMaxVersions(10);
370     AccessTestAction action = new AccessTestAction() {
371       @Override
372       public Object run() throws Exception {
373         ACCESS_CONTROLLER.preModifyColumn(ObserverContext.createAndPrepare(CP_ENV, null),
374           TEST_TABLE.getTableName(), hcd);
375         return null;
376       }
377     };
378 
379     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_ADMIN_CF);
380     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
381   }
382 
383   @Test
384   public void testDeleteColumn() throws Exception {
385     AccessTestAction action = new AccessTestAction() {
386       @Override
387       public Object run() throws Exception {
388         ACCESS_CONTROLLER.preDeleteColumn(ObserverContext.createAndPrepare(CP_ENV, null),
389           TEST_TABLE.getTableName(), TEST_FAMILY);
390         return null;
391       }
392     };
393 
394     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_ADMIN_CF);
395     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
396   }
397 
398   @Test
399   public void testTableDisable() throws Exception {
400     AccessTestAction disableTable = new AccessTestAction() {
401       @Override
402       public Object run() throws Exception {
403         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
404           TEST_TABLE.getTableName());
405         return null;
406       }
407     };
408 
409     AccessTestAction disableAclTable = new AccessTestAction() {
410       @Override
411       public Object run() throws Exception {
412         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
413             AccessControlLists.ACL_TABLE_NAME);
414         return null;
415       }
416     };
417 
418     verifyAllowed(disableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
419     verifyDenied(disableTable, USER_RW, USER_RO, USER_NONE);
420 
421     // No user should be allowed to disable _acl_ table
422     verifyDenied(disableAclTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW, USER_RO);
423   }
424 
425   @Test
426   public void testTableEnable() throws Exception {
427     AccessTestAction enableTable = new AccessTestAction() {
428       @Override
429       public Object run() throws Exception {
430         ACCESS_CONTROLLER
431             .preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName());
432         return null;
433       }
434     };
435 
436     verifyAllowed(enableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
437     verifyDenied(enableTable, USER_RW, USER_RO, USER_NONE);
438   }
439 
440   @Test
441   public void testMove() throws Exception {
442     Map<HRegionInfo, ServerName> regions;
443     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
444     try {
445       regions = table.getRegionLocations();
446     } finally {
447       table.close();
448     }
449     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
450     final ServerName server = TEST_UTIL.getHBaseCluster().getRegionServer(0).getServerName();
451     AccessTestAction action = new AccessTestAction() {
452       @Override
453       public Object run() throws Exception {
454         ACCESS_CONTROLLER.preMove(ObserverContext.createAndPrepare(CP_ENV, null),
455           firstRegion.getKey(), server, server);
456         return null;
457       }
458     };
459 
460     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
461     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
462   }
463 
464   @Test
465   public void testAssign() throws Exception {
466     Map<HRegionInfo, ServerName> regions;
467     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
468     try {
469       regions = table.getRegionLocations();
470     } finally {
471       table.close();
472     }
473     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
474 
475     AccessTestAction action = new AccessTestAction() {
476       @Override
477       public Object run() throws Exception {
478         ACCESS_CONTROLLER.preAssign(ObserverContext.createAndPrepare(CP_ENV, null),
479           firstRegion.getKey());
480         return null;
481       }
482     };
483 
484     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
485     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
486   }
487 
488   @Test
489   public void testUnassign() throws Exception {
490     Map<HRegionInfo, ServerName> regions;
491     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
492     try {
493       regions = table.getRegionLocations();
494     } finally {
495       table.close();
496     }
497     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
498 
499     AccessTestAction action = new AccessTestAction() {
500       @Override
501       public Object run() throws Exception {
502         ACCESS_CONTROLLER.preUnassign(ObserverContext.createAndPrepare(CP_ENV, null),
503           firstRegion.getKey(), false);
504         return null;
505       }
506     };
507 
508     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
509     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
510   }
511 
512   @Test
513   public void testRegionOffline() throws Exception {
514     Map<HRegionInfo, ServerName> regions;
515     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
516     try {
517       regions = table.getRegionLocations();
518     } finally {
519       table.close();
520     }
521     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
522 
523     AccessTestAction action = new AccessTestAction() {
524       @Override
525       public Object run() throws Exception {
526         ACCESS_CONTROLLER.preRegionOffline(ObserverContext.createAndPrepare(CP_ENV, null),
527           firstRegion.getKey());
528         return null;
529       }
530     };
531 
532     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
533     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
534   }
535 
536   @Test
537   public void testBalance() throws Exception {
538     AccessTestAction action = new AccessTestAction() {
539       @Override
540       public Object run() throws Exception {
541         ACCESS_CONTROLLER.preBalance(ObserverContext.createAndPrepare(CP_ENV, null));
542         return null;
543       }
544     };
545 
546     verifyAllowed(action, SUPERUSER, USER_ADMIN);
547     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
548   }
549 
550   @Test
551   public void testBalanceSwitch() throws Exception {
552     AccessTestAction action = new AccessTestAction() {
553       @Override
554       public Object run() throws Exception {
555         ACCESS_CONTROLLER.preBalanceSwitch(ObserverContext.createAndPrepare(CP_ENV, null), true);
556         return null;
557       }
558     };
559 
560     verifyAllowed(action, SUPERUSER, USER_ADMIN);
561     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
562   }
563 
564   @Test
565   public void testShutdown() throws Exception {
566     AccessTestAction action = new AccessTestAction() {
567       @Override
568       public Object run() throws Exception {
569         ACCESS_CONTROLLER.preShutdown(ObserverContext.createAndPrepare(CP_ENV, null));
570         return null;
571       }
572     };
573 
574     verifyAllowed(action, SUPERUSER, USER_ADMIN);
575     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
576   }
577 
578   @Test
579   public void testStopMaster() throws Exception {
580     AccessTestAction action = new AccessTestAction() {
581       @Override
582       public Object run() throws Exception {
583         ACCESS_CONTROLLER.preStopMaster(ObserverContext.createAndPrepare(CP_ENV, null));
584         return null;
585       }
586     };
587 
588     verifyAllowed(action, SUPERUSER, USER_ADMIN);
589     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
590   }
591 
592   private void verifyWrite(AccessTestAction action) throws Exception {
593     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
594     verifyDenied(action, USER_NONE, USER_RO);
595   }
596 
597   @Test
598   public void testSplit() throws Exception {
599     AccessTestAction action = new AccessTestAction() {
600       @Override
601       public Object run() throws Exception {
602         ACCESS_CONTROLLER.preSplit(ObserverContext.createAndPrepare(RCP_ENV, null));
603         return null;
604       }
605     };
606 
607     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
608     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
609   }
610 
611   @Test
612   public void testSplitWithSplitRow() throws Exception {
613     AccessTestAction action = new AccessTestAction() {
614       @Override
615       public Object run() throws Exception {
616         ACCESS_CONTROLLER.preSplit(
617             ObserverContext.createAndPrepare(RCP_ENV, null),
618             TEST_ROW);
619         return null;
620       }
621     };
622 
623     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
624     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
625   }
626 
627   @Test
628   public void testMergeRegions() throws Exception {
629 
630     final List<HRegion> regions = TEST_UTIL.getHBaseCluster().findRegionsForTable(TEST_TABLE.getTableName());
631 
632     AccessTestAction action = new AccessTestAction() {
633       @Override
634       public Object run() throws Exception {
635         ACCESS_CONTROLLER.preMerge(
636             ObserverContext.createAndPrepare(RSCP_ENV, null),
637             regions.get(0),regions.get(1));
638         return null;
639       }
640     };
641 
642     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
643     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
644   }
645 
646   @Test
647   public void testFlush() throws Exception {
648     AccessTestAction action = new AccessTestAction() {
649       @Override
650       public Object run() throws Exception {
651         ACCESS_CONTROLLER.preFlush(ObserverContext.createAndPrepare(RCP_ENV, null));
652         return null;
653       }
654     };
655 
656     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
657     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
658   }
659 
660   @Test
661   public void testCompact() throws Exception {
662     AccessTestAction action = new AccessTestAction() {
663       @Override
664       public Object run() throws Exception {
665         ACCESS_CONTROLLER.preCompact(ObserverContext.createAndPrepare(RCP_ENV, null), null, null,
666           ScanType.COMPACT_RETAIN_DELETES);
667         return null;
668       }
669     };
670 
671     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
672     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
673   }
674 
675   @Test
676   public void testPreCompactSelection() throws Exception {
677     AccessTestAction action = new AccessTestAction() {
678       @Override
679       public Object run() throws Exception {
680         ACCESS_CONTROLLER.preCompactSelection(ObserverContext.createAndPrepare(RCP_ENV, null), null, null);
681         return null;
682       }
683     };
684 
685     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
686     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
687   }
688 
689   private void verifyRead(AccessTestAction action) throws Exception {
690     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO);
691     verifyDenied(action, USER_NONE);
692   }
693 
694   private void verifyReadWrite(AccessTestAction action) throws Exception {
695     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
696     verifyDenied(action, USER_NONE, USER_RO);
697   }
698 
699   @Test
700   public void testRead() throws Exception {
701     // get action
702     AccessTestAction getAction = new AccessTestAction() {
703       @Override
704       public Object run() throws Exception {
705         Get g = new Get(TEST_ROW);
706         g.addFamily(TEST_FAMILY);
707         HTable t = new HTable(conf, TEST_TABLE.getTableName());
708         try {
709           t.get(g);
710         } finally {
711           t.close();
712         }
713         return null;
714       }
715     };
716     verifyRead(getAction);
717 
718     // action for scanning
719     AccessTestAction scanAction = new AccessTestAction() {
720       @Override
721       public Object run() throws Exception {
722         Scan s = new Scan();
723         s.addFamily(TEST_FAMILY);
724 
725         HTable table = new HTable(conf, TEST_TABLE.getTableName());
726         try {
727           ResultScanner scanner = table.getScanner(s);
728           try {
729             for (Result r = scanner.next(); r != null; r = scanner.next()) {
730               // do nothing
731             }
732           } catch (IOException e) {
733           } finally {
734             scanner.close();
735           }
736         } finally {
737           table.close();
738         }
739         return null;
740       }
741     };
742     verifyRead(scanAction);
743   }
744 
745   @Test
746   // test put, delete, increment
747   public void testWrite() throws Exception {
748     // put action
749     AccessTestAction putAction = new AccessTestAction() {
750       @Override
751       public Object run() throws Exception {
752         Put p = new Put(TEST_ROW);
753         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
754         HTable t = new HTable(conf, TEST_TABLE.getTableName());
755         try {
756           t.put(p);
757         } finally {
758           t.close();
759         }
760         return null;
761       }
762     };
763     verifyWrite(putAction);
764 
765     // delete action
766     AccessTestAction deleteAction = new AccessTestAction() {
767       @Override
768       public Object run() throws Exception {
769         Delete d = new Delete(TEST_ROW);
770         d.deleteFamily(TEST_FAMILY);
771         HTable t = new HTable(conf, TEST_TABLE.getTableName());
772         try {
773           t.delete(d);
774         } finally {
775           t.close();
776         }
777         return null;
778       }
779     };
780     verifyWrite(deleteAction);
781 
782     // increment action
783     AccessTestAction incrementAction = new AccessTestAction() {
784       @Override
785       public Object run() throws Exception {
786         Increment inc = new Increment(TEST_ROW);
787         inc.addColumn(TEST_FAMILY, TEST_QUALIFIER, 1);
788         HTable t = new HTable(conf, TEST_TABLE.getTableName());
789         try {
790           t.increment(inc);
791         } finally {
792           t.close();
793         }
794         return null;
795       }
796     };
797     verifyWrite(incrementAction);
798   }
799 
800   @Test
801   public void testReadWrite() throws Exception {
802     // action for checkAndDelete
803     AccessTestAction checkAndDeleteAction = new AccessTestAction() {
804       @Override
805       public Object run() throws Exception {
806         Delete d = new Delete(TEST_ROW);
807         d.deleteFamily(TEST_FAMILY);
808         HTable t = new HTable(conf, TEST_TABLE.getTableName());
809         try {
810           t.checkAndDelete(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
811             Bytes.toBytes("test_value"), d);
812         } finally {
813           t.close();
814         }
815         return null;
816       }
817     };
818     verifyReadWrite(checkAndDeleteAction);
819 
820     // action for checkAndPut()
821     AccessTestAction checkAndPut = new AccessTestAction() {
822       @Override
823       public Object run() throws Exception {
824         Put p = new Put(TEST_ROW);
825         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
826         HTable t = new HTable(conf, TEST_TABLE.getTableName());
827         try {
828           t.checkAndPut(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
829            Bytes.toBytes("test_value"), p);
830         } finally {
831           t.close();
832         }
833         return null;
834       }
835     };
836     verifyReadWrite(checkAndPut);
837   }
838 
839   @Test
840   public void testBulkLoad() throws Exception {
841     FileSystem fs = TEST_UTIL.getTestFileSystem();
842     final Path dir = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoad");
843     fs.mkdirs(dir);
844     //need to make it globally writable
845     //so users creating HFiles have write permissions
846     fs.setPermission(dir, FsPermission.valueOf("-rwxrwxrwx"));
847 
848     AccessTestAction bulkLoadAction = new AccessTestAction() {
849       @Override
850       public Object run() throws Exception {
851         int numRows = 3;
852 
853         //Making the assumption that the test table won't split between the range
854         byte[][][] hfileRanges = {{{(byte)0}, {(byte)9}}};
855 
856         Path bulkLoadBasePath = new Path(dir, new Path(User.getCurrent().getName()));
857         new BulkLoadHelper(bulkLoadBasePath)
858             .bulkLoadHFile(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_QUALIFIER, hfileRanges, numRows);
859 
860         return null;
861       }
862     };
863 
864     // User performing bulk loads must have privilege to read table metadata
865     // (ADMIN or CREATE)
866     verifyAllowed(bulkLoadAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
867     verifyDenied(bulkLoadAction, USER_RW, USER_NONE, USER_RO);
868 
869     // Reinit after the bulk upload
870     TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE.getTableName());
871     TEST_UTIL.getHBaseAdmin().enableTable(TEST_TABLE.getTableName());
872   }
873 
874   public class BulkLoadHelper {
875     private final FileSystem fs;
876     private final Path loadPath;
877     private final Configuration conf;
878 
879     public BulkLoadHelper(Path loadPath) throws IOException {
880       fs = TEST_UTIL.getTestFileSystem();
881       conf = TEST_UTIL.getConfiguration();
882       loadPath = loadPath.makeQualified(fs);
883       this.loadPath = loadPath;
884     }
885 
886     private void createHFile(Path path,
887         byte[] family, byte[] qualifier,
888         byte[] startKey, byte[] endKey, int numRows) throws IOException {
889 
890       HFile.Writer writer = null;
891       long now = System.currentTimeMillis();
892       try {
893         HFileContext context = new HFileContextBuilder().build();
894         writer = HFile.getWriterFactory(conf, new CacheConfig(conf))
895             .withPath(fs, path)
896             .withFileContext(context)
897             .create();
898         // subtract 2 since numRows doesn't include boundary keys
899         for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, true, numRows-2)) {
900           KeyValue kv = new KeyValue(key, family, qualifier, now, key);
901           writer.append(kv);
902         }
903       } finally {
904         if(writer != null)
905           writer.close();
906       }
907     }
908 
909     private void bulkLoadHFile(
910         TableName tableName,
911         byte[] family,
912         byte[] qualifier,
913         byte[][][] hfileRanges,
914         int numRowsPerRange) throws Exception {
915 
916       Path familyDir = new Path(loadPath, Bytes.toString(family));
917       fs.mkdirs(familyDir);
918       int hfileIdx = 0;
919       for (byte[][] range : hfileRanges) {
920         byte[] from = range[0];
921         byte[] to = range[1];
922         createHFile(new Path(familyDir, "hfile_"+(hfileIdx++)),
923             family, qualifier, from, to, numRowsPerRange);
924       }
925       //set global read so RegionServer can move it
926       setPermission(loadPath, FsPermission.valueOf("-rwxrwxrwx"));
927 
928       HTable table = new HTable(conf, tableName);
929       try {
930         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
931         TEST_UTIL.waitTableEnabled(admin, tableName.getName());
932         LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
933         loader.doBulkLoad(loadPath, table);
934       } finally {
935         table.close();
936       }
937     }
938 
939     public void setPermission(Path dir, FsPermission perm) throws IOException {
940       if(!fs.getFileStatus(dir).isDir()) {
941         fs.setPermission(dir,perm);
942       }
943       else {
944         for(FileStatus el : fs.listStatus(dir)) {
945           fs.setPermission(el.getPath(), perm);
946           setPermission(el.getPath() , perm);
947         }
948       }
949     }
950   }
951 
952   @Test
953   public void testAppend() throws Exception {
954 
955     AccessTestAction appendAction = new AccessTestAction() {
956       @Override
957       public Object run() throws Exception {
958         byte[] row = TEST_ROW;
959         byte[] qualifier = TEST_QUALIFIER;
960         Put put = new Put(row);
961         put.add(TEST_FAMILY, qualifier, Bytes.toBytes(1));
962         Append append = new Append(row);
963         append.add(TEST_FAMILY, qualifier, Bytes.toBytes(2));
964         HTable t = new HTable(conf, TEST_TABLE.getTableName());
965         try {
966           t.put(put);
967           t.append(append);
968         } finally {
969           t.close();
970         }
971         return null;
972       }
973     };
974 
975     verifyAllowed(appendAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
976     verifyDenied(appendAction, USER_RO, USER_NONE);
977   }
978 
979   @Test
980   public void testGrantRevoke() throws Exception {
981     AccessTestAction grantAction = new AccessTestAction() {
982       @Override
983       public Object run() throws Exception {
984         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
985         try {
986           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
987           AccessControlService.BlockingInterface protocol =
988             AccessControlService.newBlockingStub(service);
989           ProtobufUtil.grant(protocol, USER_RO.getShortName(), TEST_TABLE.getTableName(),
990             TEST_FAMILY, null, Action.READ);
991         } finally {
992           acl.close();
993         }
994         return null;
995       }
996     };
997 
998     AccessTestAction revokeAction = new AccessTestAction() {
999       @Override
1000       public Object run() throws Exception {
1001         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1002         try {
1003           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
1004           AccessControlService.BlockingInterface protocol =
1005             AccessControlService.newBlockingStub(service);
1006           ProtobufUtil.revoke(protocol, USER_RO.getShortName(), TEST_TABLE.getTableName(),
1007             TEST_FAMILY, null, Action.READ);
1008         } finally {
1009           acl.close();
1010         }
1011         return null;
1012       }
1013     };
1014 
1015     AccessTestAction getTablePermissionsAction = new AccessTestAction() {
1016       @Override
1017       public Object run() throws Exception {
1018         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1019         try {
1020           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
1021           AccessControlService.BlockingInterface protocol =
1022             AccessControlService.newBlockingStub(service);
1023           ProtobufUtil.getUserPermissions(protocol, TEST_TABLE.getTableName());
1024         } finally {
1025           acl.close();
1026         }
1027         return null;
1028       }
1029     };
1030 
1031     AccessTestAction getGlobalPermissionsAction = new AccessTestAction() {
1032       @Override
1033       public Object run() throws Exception {
1034         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1035         try {
1036           BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1037           AccessControlService.BlockingInterface protocol =
1038             AccessControlService.newBlockingStub(service);
1039           ProtobufUtil.getUserPermissions(protocol);
1040         } finally {
1041           acl.close();
1042         }
1043         return null;
1044       }
1045     };
1046 
1047     verifyAllowed(grantAction, SUPERUSER, USER_ADMIN, USER_OWNER);
1048     verifyDenied(grantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
1049 
1050     verifyAllowed(revokeAction, SUPERUSER, USER_ADMIN, USER_OWNER);
1051     verifyDenied(revokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
1052 
1053     verifyAllowed(getTablePermissionsAction, SUPERUSER, USER_ADMIN, USER_OWNER);
1054     verifyDenied(getTablePermissionsAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
1055 
1056     verifyAllowed(getGlobalPermissionsAction, SUPERUSER, USER_ADMIN);
1057     verifyDeniedWithException(getGlobalPermissionsAction, USER_CREATE,
1058         USER_OWNER, USER_RW, USER_RO, USER_NONE);
1059   }
1060 
1061   @Test
1062   public void testPostGrantRevoke() throws Exception {
1063     final TableName tableName =
1064         TableName.valueOf("TempTable");
1065     final byte[] family1 = Bytes.toBytes("f1");
1066     final byte[] family2 = Bytes.toBytes("f2");
1067     final byte[] qualifier = Bytes.toBytes("q");
1068 
1069     // create table
1070     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1071     if (admin.tableExists(tableName)) {
1072       admin.disableTable(tableName);
1073       admin.deleteTable(tableName);
1074     }
1075     HTableDescriptor htd = new HTableDescriptor(tableName);
1076     htd.addFamily(new HColumnDescriptor(family1));
1077     htd.addFamily(new HColumnDescriptor(family2));
1078     admin.createTable(htd);
1079     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1080 
1081     // create temp users
1082     User tblUser = User
1083         .createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]);
1084     User gblUser = User
1085         .createUserForTesting(TEST_UTIL.getConfiguration(), "gbluser", new String[0]);
1086 
1087     // prepare actions:
1088     AccessTestAction putActionAll = new AccessTestAction() {
1089       @Override
1090       public Object run() throws Exception {
1091         Put p = new Put(Bytes.toBytes("a"));
1092         p.add(family1, qualifier, Bytes.toBytes("v1"));
1093         p.add(family2, qualifier, Bytes.toBytes("v2"));
1094         HTable t = new HTable(conf, tableName);
1095         try {
1096           t.put(p);
1097         } finally {
1098           t.close();
1099         }
1100         return null;
1101       }
1102     };
1103 
1104     AccessTestAction putAction1 = new AccessTestAction() {
1105       @Override
1106       public Object run() throws Exception {
1107         Put p = new Put(Bytes.toBytes("a"));
1108         p.add(family1, qualifier, Bytes.toBytes("v1"));
1109         HTable t = new HTable(conf, tableName);
1110         try {
1111           t.put(p);
1112         } finally {
1113           t.close();
1114         }
1115         return null;
1116       }
1117     };
1118 
1119     AccessTestAction putAction2 = new AccessTestAction() {
1120       @Override
1121       public Object run() throws Exception {
1122         Put p = new Put(Bytes.toBytes("a"));
1123         p.add(family2, qualifier, Bytes.toBytes("v2"));
1124         HTable t = new HTable(conf, tableName);
1125         try {
1126           t.put(p);
1127         } finally {
1128           t.close();
1129         }
1130         return null;
1131       }
1132     };
1133 
1134     AccessTestAction getActionAll = new AccessTestAction() {
1135       @Override
1136       public Object run() throws Exception {
1137         Get g = new Get(TEST_ROW);
1138         g.addFamily(family1);
1139         g.addFamily(family2);
1140         HTable t = new HTable(conf, tableName);
1141         try {
1142           t.get(g);
1143         } finally {
1144           t.close();
1145         }
1146         return null;
1147       }
1148     };
1149 
1150     AccessTestAction getAction1 = new AccessTestAction() {
1151       @Override
1152       public Object run() throws Exception {
1153         Get g = new Get(TEST_ROW);
1154         g.addFamily(family1);
1155         HTable t = new HTable(conf, tableName);
1156         try {
1157           t.get(g);
1158         } finally {
1159           t.close();
1160         }
1161         return null;
1162       }
1163     };
1164 
1165     AccessTestAction getAction2 = new AccessTestAction() {
1166       @Override
1167       public Object run() throws Exception {
1168         Get g = new Get(TEST_ROW);
1169         g.addFamily(family2);
1170         HTable t = new HTable(conf, tableName);
1171         try {
1172           t.get(g);
1173         } finally {
1174           t.close();
1175         }
1176         return null;
1177       }
1178     };
1179 
1180     AccessTestAction deleteActionAll = new AccessTestAction() {
1181       @Override
1182       public Object run() throws Exception {
1183         Delete d = new Delete(TEST_ROW);
1184         d.deleteFamily(family1);
1185         d.deleteFamily(family2);
1186         HTable t = new HTable(conf, tableName);
1187         try {
1188           t.delete(d);
1189         } finally {
1190           t.close();
1191         }
1192         return null;
1193       }
1194     };
1195 
1196     AccessTestAction deleteAction1 = new AccessTestAction() {
1197       @Override
1198       public Object run() throws Exception {
1199         Delete d = new Delete(TEST_ROW);
1200         d.deleteFamily(family1);
1201         HTable t = new HTable(conf, tableName);
1202         try {
1203           t.delete(d);
1204         } finally {
1205           t.close();
1206         }
1207         return null;
1208       }
1209     };
1210 
1211     AccessTestAction deleteAction2 = new AccessTestAction() {
1212       @Override
1213       public Object run() throws Exception {
1214         Delete d = new Delete(TEST_ROW);
1215         d.deleteFamily(family2);
1216         HTable t = new HTable(conf, tableName);
1217         try {
1218           t.delete(d);
1219         } finally {
1220           t.close();
1221         }
1222         return null;
1223       }
1224     };
1225 
1226     // initial check:
1227     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1228     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1229     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1230 
1231     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1232     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1233     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1234 
1235     // grant table read permission
1236     grantGlobal(TEST_UTIL, gblUser.getShortName(),
1237       Permission.Action.READ);
1238     grantOnTable(TEST_UTIL, tblUser.getShortName(),
1239       tableName, null, null,
1240       Permission.Action.READ);
1241 
1242     // check
1243     verifyAllowed(tblUser, getActionAll, getAction1, getAction2);
1244     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1245     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1246 
1247     verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1248     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1249     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1250 
1251     // grant table write permission while revoking read permissions
1252     grantGlobal(TEST_UTIL, gblUser.getShortName(),
1253       Permission.Action.WRITE);
1254     grantOnTable(TEST_UTIL, tblUser.getShortName(),
1255       tableName, null, null,
1256       Permission.Action.WRITE);
1257 
1258     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1259     verifyAllowed(tblUser, putActionAll, putAction1, putAction2);
1260     verifyAllowed(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1261 
1262     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1263     verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1264     verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1265 
1266     // revoke table permissions
1267     revokeGlobal(TEST_UTIL, gblUser.getShortName());
1268     revokeFromTable(TEST_UTIL, tblUser.getShortName(),
1269       tableName, null, null);
1270 
1271     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1272     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1273     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1274 
1275     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1276     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1277     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1278 
1279     // grant column family read permission
1280     grantGlobal(TEST_UTIL, gblUser.getShortName(),
1281       Permission.Action.READ);
1282     grantOnTable(TEST_UTIL, tblUser.getShortName(),
1283       tableName, family1, null, Permission.Action.READ);
1284 
1285     // Access should be denied for family2
1286     verifyAllowed(tblUser, getActionAll, getAction1);
1287     verifyDenied(tblUser, getAction2);
1288     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1289     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1290 
1291     verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1292     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1293     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1294 
1295     // grant column family write permission
1296     grantGlobal(TEST_UTIL, gblUser.getShortName(),
1297       Permission.Action.WRITE);
1298     grantOnTable(TEST_UTIL, tblUser.getShortName(),
1299       tableName, family2, null, Permission.Action.WRITE);
1300 
1301     // READ from family1, WRITE to family2 are allowed
1302     verifyAllowed(tblUser, getActionAll, getAction1);
1303     verifyAllowed(tblUser, putAction2, deleteAction2);
1304     verifyDenied(tblUser, getAction2);
1305     verifyDenied(tblUser, putActionAll, putAction1);
1306     verifyDenied(tblUser, deleteActionAll, deleteAction1);
1307 
1308     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1309     verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1310     verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1311 
1312     // revoke column family permission
1313     revokeGlobal(TEST_UTIL, gblUser.getShortName());
1314     revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null);
1315 
1316     // Revoke on family2 should not have impact on family1 permissions
1317     verifyAllowed(tblUser, getActionAll, getAction1);
1318     verifyDenied(tblUser, getAction2);
1319     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1320     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1321 
1322     // Should not have access as global permissions are completely revoked
1323     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1324     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1325     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1326 
1327     // delete table
1328     admin.disableTable(tableName);
1329     admin.deleteTable(tableName);
1330   }
1331 
1332   private boolean hasFoundUserPermission(UserPermission userPermission, List<UserPermission> perms) {
1333     return perms.contains(userPermission);
1334   }
1335 
1336   @Test
1337   public void testPostGrantRevokeAtQualifierLevel() throws Exception {
1338     final TableName tableName =
1339         TableName.valueOf("testGrantRevokeAtQualifierLevel");
1340     final byte[] family1 = Bytes.toBytes("f1");
1341     final byte[] family2 = Bytes.toBytes("f2");
1342     final byte[] qualifier = Bytes.toBytes("q");
1343 
1344     // create table
1345     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1346     if (admin.tableExists(tableName)) {
1347       admin.disableTable(tableName);
1348       admin.deleteTable(tableName);
1349     }
1350     HTableDescriptor htd = new HTableDescriptor(tableName);
1351     htd.addFamily(new HColumnDescriptor(family1));
1352     htd.addFamily(new HColumnDescriptor(family2));
1353     admin.createTable(htd);
1354     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1355 
1356     // create temp users
1357     User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1358 
1359     AccessTestAction getQualifierAction = new AccessTestAction() {
1360       @Override
1361       public Object run() throws Exception {
1362         Get g = new Get(TEST_ROW);
1363         g.addColumn(family1, qualifier);
1364         HTable t = new HTable(conf, tableName);
1365         try {
1366           t.get(g);
1367         } finally {
1368           t.close();
1369         }
1370         return null;
1371       }
1372     };
1373 
1374     AccessTestAction putQualifierAction = new AccessTestAction() {
1375       @Override
1376       public Object run() throws Exception {
1377         Put p = new Put(TEST_ROW);
1378         p.add(family1, qualifier, Bytes.toBytes("v1"));
1379         HTable t = new HTable(conf, tableName);
1380         try {
1381           t.put(p);
1382         } finally {
1383           t.close();
1384         }
1385         return null;
1386       }
1387     };
1388 
1389     AccessTestAction deleteQualifierAction = new AccessTestAction() {
1390       @Override
1391       public Object run() throws Exception {
1392         Delete d = new Delete(TEST_ROW);
1393         d.deleteColumn(family1, qualifier);
1394         // d.deleteFamily(family1);
1395         HTable t = new HTable(conf, tableName);
1396         try {
1397           t.delete(d);
1398         } finally {
1399           t.close();
1400         }
1401         return null;
1402       }
1403     };
1404 
1405     revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, null);
1406 
1407     verifyDenied(user, getQualifierAction);
1408     verifyDenied(user, putQualifierAction);
1409     verifyDenied(user, deleteQualifierAction);
1410 
1411     grantOnTable(TEST_UTIL, user.getShortName(),
1412       tableName, family1, qualifier,
1413       Permission.Action.READ);
1414 
1415     verifyAllowed(user, getQualifierAction);
1416     verifyDenied(user, putQualifierAction);
1417     verifyDenied(user, deleteQualifierAction);
1418 
1419     // only grant write permission
1420     // TODO: comment this portion after HBASE-3583
1421     grantOnTable(TEST_UTIL, user.getShortName(),
1422       tableName, family1, qualifier,
1423       Permission.Action.WRITE);
1424 
1425     verifyDenied(user, getQualifierAction);
1426     verifyAllowed(user, putQualifierAction);
1427     verifyAllowed(user, deleteQualifierAction);
1428 
1429     // grant both read and write permission
1430     grantOnTable(TEST_UTIL, user.getShortName(),
1431       tableName, family1, qualifier,
1432       Permission.Action.READ, Permission.Action.WRITE);
1433 
1434     verifyAllowed(user, getQualifierAction);
1435     verifyAllowed(user, putQualifierAction);
1436     verifyAllowed(user, deleteQualifierAction);
1437 
1438     // revoke family level permission won't impact column level
1439     revokeFromTable(TEST_UTIL, user.getShortName(),
1440       tableName, family1, qualifier);
1441 
1442     verifyDenied(user, getQualifierAction);
1443     verifyDenied(user, putQualifierAction);
1444     verifyDenied(user, deleteQualifierAction);
1445 
1446     // delete table
1447     admin.disableTable(tableName);
1448     admin.deleteTable(tableName);
1449   }
1450 
1451   @Test
1452   public void testPermissionList() throws Exception {
1453     final TableName tableName =
1454         TableName.valueOf("testPermissionList");
1455     final byte[] family1 = Bytes.toBytes("f1");
1456     final byte[] family2 = Bytes.toBytes("f2");
1457     final byte[] qualifier = Bytes.toBytes("q");
1458 
1459     // create table
1460     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1461     if (admin.tableExists(tableName)) {
1462       admin.disableTable(tableName);
1463       admin.deleteTable(tableName);
1464     }
1465     HTableDescriptor htd = new HTableDescriptor(tableName);
1466     htd.addFamily(new HColumnDescriptor(family1));
1467     htd.addFamily(new HColumnDescriptor(family2));
1468     htd.setOwner(USER_OWNER);
1469     admin.createTable(htd);
1470     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1471 
1472     List<UserPermission> perms;
1473 
1474     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1475     try {
1476       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1477       AccessControlService.BlockingInterface protocol =
1478         AccessControlService.newBlockingStub(service);
1479       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1480     } finally {
1481       acl.close();
1482     }
1483 
1484     UserPermission ownerperm = new UserPermission(
1485       Bytes.toBytes(USER_OWNER.getName()), tableName, null, Action.values());
1486     assertTrue("Owner should have all permissions on table",
1487       hasFoundUserPermission(ownerperm, perms));
1488 
1489     User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1490     byte[] userName = Bytes.toBytes(user.getShortName());
1491 
1492     UserPermission up = new UserPermission(userName,
1493       tableName, family1, qualifier, Permission.Action.READ);
1494     assertFalse("User should not be granted permission: " + up.toString(),
1495       hasFoundUserPermission(up, perms));
1496 
1497     // grant read permission
1498     grantOnTable(TEST_UTIL, user.getShortName(),
1499       tableName, family1, qualifier, Permission.Action.READ);
1500 
1501     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1502     try {
1503       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1504       AccessControlService.BlockingInterface protocol =
1505         AccessControlService.newBlockingStub(service);
1506       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1507     } finally {
1508       acl.close();
1509     }
1510 
1511     UserPermission upToVerify = new UserPermission(
1512       userName, tableName, family1, qualifier, Permission.Action.READ);
1513     assertTrue("User should be granted permission: " + upToVerify.toString(),
1514       hasFoundUserPermission(upToVerify, perms));
1515 
1516     upToVerify = new UserPermission(
1517       userName, tableName, family1, qualifier, Permission.Action.WRITE);
1518     assertFalse("User should not be granted permission: " + upToVerify.toString(),
1519       hasFoundUserPermission(upToVerify, perms));
1520 
1521     // grant read+write
1522     grantOnTable(TEST_UTIL, user.getShortName(),
1523       tableName, family1, qualifier,
1524       Permission.Action.WRITE, Permission.Action.READ);
1525 
1526     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1527     try {
1528       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1529       AccessControlService.BlockingInterface protocol =
1530         AccessControlService.newBlockingStub(service);
1531       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1532     } finally {
1533       acl.close();
1534     }
1535 
1536     upToVerify = new UserPermission(userName, tableName, family1,
1537       qualifier, Permission.Action.WRITE, Permission.Action.READ);
1538     assertTrue("User should be granted permission: " + upToVerify.toString(),
1539       hasFoundUserPermission(upToVerify, perms));
1540 
1541     // revoke
1542     revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1543       Permission.Action.WRITE, Permission.Action.READ);
1544 
1545     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1546     try {
1547       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1548       AccessControlService.BlockingInterface protocol =
1549         AccessControlService.newBlockingStub(service);
1550       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1551     } finally {
1552       acl.close();
1553     }
1554 
1555     assertFalse("User should not be granted permission: " + upToVerify.toString(),
1556       hasFoundUserPermission(upToVerify, perms));
1557 
1558     // disable table before modification
1559     admin.disableTable(tableName);
1560 
1561     User newOwner = User.createUserForTesting(conf, "new_owner", new String[] {});
1562     htd.setOwner(newOwner);
1563     admin.modifyTable(tableName, htd);
1564 
1565     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1566     try {
1567       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1568       AccessControlService.BlockingInterface protocol =
1569         AccessControlService.newBlockingStub(service);
1570       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1571     } finally {
1572       acl.close();
1573     }
1574 
1575     UserPermission newOwnerperm = new UserPermission(
1576       Bytes.toBytes(newOwner.getName()), tableName, null, Action.values());
1577     assertTrue("New owner should have all permissions on table",
1578       hasFoundUserPermission(newOwnerperm, perms));
1579 
1580     // delete table
1581     admin.deleteTable(tableName);
1582   }
1583 
1584   @Test
1585   public void testGlobalPermissionList() throws Exception {
1586     List<UserPermission> perms;
1587     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1588     try {
1589       BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1590       AccessControlService.BlockingInterface protocol =
1591         AccessControlService.newBlockingStub(service);
1592       perms = ProtobufUtil.getUserPermissions(protocol);
1593     } finally {
1594       acl.close();
1595     }
1596     UserPermission adminPerm = new UserPermission(Bytes.toBytes(USER_ADMIN.getShortName()),
1597       AccessControlLists.ACL_TABLE_NAME, null, null, Bytes.toBytes("ACRW"));
1598     assertTrue("Only user admin has permission on table _acl_ per setup",
1599       perms.size() == 1 && hasFoundUserPermission(adminPerm, perms));
1600   }
1601 
1602   /** global operations */
1603   private void verifyGlobal(AccessTestAction action) throws Exception {
1604     verifyAllowed(action, SUPERUSER);
1605 
1606     verifyDenied(action, USER_CREATE, USER_RW, USER_NONE, USER_RO);
1607   }
1608 
1609   public void checkGlobalPerms(Permission.Action... actions) throws IOException {
1610     Permission[] perms = new Permission[actions.length];
1611     for (int i = 0; i < actions.length; i++) {
1612       perms[i] = new Permission(actions[i]);
1613     }
1614     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
1615     for (Action a : actions) {
1616       request.addPermission(AccessControlProtos.Permission.newBuilder()
1617           .setType(AccessControlProtos.Permission.Type.Global)
1618           .setGlobalPermission(
1619               AccessControlProtos.GlobalPermission.newBuilder()
1620                   .addAction(ProtobufUtil.toPermissionAction(a)).build()));
1621     }
1622     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1623     try {
1624       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1625       AccessControlService.BlockingInterface protocol =
1626         AccessControlService.newBlockingStub(channel);
1627       try {
1628         protocol.checkPermissions(null, request.build());
1629       } catch (ServiceException se) {
1630         ProtobufUtil.toIOException(se);
1631       }
1632     } finally {
1633       acl.close();
1634     }
1635   }
1636 
1637   public void checkTablePerms(TableName table, byte[] family, byte[] column,
1638       Permission.Action... actions) throws IOException {
1639     Permission[] perms = new Permission[actions.length];
1640     for (int i = 0; i < actions.length; i++) {
1641       perms[i] = new TablePermission(table, family, column, actions[i]);
1642     }
1643 
1644     checkTablePerms(table, perms);
1645   }
1646 
1647   public void checkTablePerms(TableName table, Permission... perms) throws IOException {
1648     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
1649     for (Permission p : perms) {
1650       request.addPermission(ProtobufUtil.toPermission(p));
1651     }
1652     HTable acl = new HTable(conf, table);
1653     try {
1654       AccessControlService.BlockingInterface protocol =
1655         AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
1656       try {
1657         protocol.checkPermissions(null, request.build());
1658       } catch (ServiceException se) {
1659         ProtobufUtil.toIOException(se);
1660       }
1661     } finally {
1662       acl.close();
1663     }
1664   }
1665 
1666   @Test
1667   public void testCheckPermissions() throws Exception {
1668     // --------------------------------------
1669     // test global permissions
1670     AccessTestAction globalAdmin = new AccessTestAction() {
1671       @Override
1672       public Void run() throws Exception {
1673         checkGlobalPerms(Permission.Action.ADMIN);
1674         return null;
1675       }
1676     };
1677     // verify that only superuser can admin
1678     verifyGlobal(globalAdmin);
1679 
1680     // --------------------------------------
1681     // test multiple permissions
1682     AccessTestAction globalReadWrite = new AccessTestAction() {
1683       @Override
1684       public Void run() throws Exception {
1685         checkGlobalPerms(Permission.Action.READ, Permission.Action.WRITE);
1686         return null;
1687       }
1688     };
1689 
1690     verifyGlobal(globalReadWrite);
1691 
1692     // --------------------------------------
1693     // table/column/qualifier level permissions
1694     final byte[] TEST_Q1 = Bytes.toBytes("q1");
1695     final byte[] TEST_Q2 = Bytes.toBytes("q2");
1696 
1697     User userTable = User.createUserForTesting(conf, "user_check_perms_table", new String[0]);
1698     User userColumn = User.createUserForTesting(conf, "user_check_perms_family", new String[0]);
1699     User userQualifier = User.createUserForTesting(conf, "user_check_perms_q", new String[0]);
1700 
1701     grantOnTable(TEST_UTIL, userTable.getShortName(),
1702       TEST_TABLE.getTableName(), null, null,
1703       Permission.Action.READ);
1704     grantOnTable(TEST_UTIL, userColumn.getShortName(),
1705       TEST_TABLE.getTableName(), TEST_FAMILY, null,
1706       Permission.Action.READ);
1707     grantOnTable(TEST_UTIL, userQualifier.getShortName(),
1708       TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1,
1709       Permission.Action.READ);
1710 
1711     AccessTestAction tableRead = new AccessTestAction() {
1712       @Override
1713       public Void run() throws Exception {
1714         checkTablePerms(TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
1715         return null;
1716       }
1717     };
1718 
1719     AccessTestAction columnRead = new AccessTestAction() {
1720       @Override
1721       public Void run() throws Exception {
1722         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ);
1723         return null;
1724       }
1725     };
1726 
1727     AccessTestAction qualifierRead = new AccessTestAction() {
1728       @Override
1729       public Void run() throws Exception {
1730         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1731         return null;
1732       }
1733     };
1734 
1735     AccessTestAction multiQualifierRead = new AccessTestAction() {
1736       @Override
1737       public Void run() throws Exception {
1738         checkTablePerms(TEST_TABLE.getTableName(), new Permission[] {
1739             new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ),
1740             new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q2, Permission.Action.READ), });
1741         return null;
1742       }
1743     };
1744 
1745     AccessTestAction globalAndTableRead = new AccessTestAction() {
1746       @Override
1747       public Void run() throws Exception {
1748         checkTablePerms(TEST_TABLE.getTableName(), new Permission[] { new Permission(Permission.Action.READ),
1749             new TablePermission(TEST_TABLE.getTableName(), null, (byte[]) null, Permission.Action.READ), });
1750         return null;
1751       }
1752     };
1753 
1754     AccessTestAction noCheck = new AccessTestAction() {
1755       @Override
1756       public Void run() throws Exception {
1757         checkTablePerms(TEST_TABLE.getTableName(), new Permission[0]);
1758         return null;
1759       }
1760     };
1761 
1762     verifyAllowed(tableRead, SUPERUSER, userTable);
1763     verifyDenied(tableRead, userColumn, userQualifier);
1764 
1765     verifyAllowed(columnRead, SUPERUSER, userTable, userColumn);
1766     verifyDenied(columnRead, userQualifier);
1767 
1768     verifyAllowed(qualifierRead, SUPERUSER, userTable, userColumn, userQualifier);
1769 
1770     verifyAllowed(multiQualifierRead, SUPERUSER, userTable, userColumn);
1771     verifyDenied(multiQualifierRead, userQualifier);
1772 
1773     verifyAllowed(globalAndTableRead, SUPERUSER);
1774     verifyDenied(globalAndTableRead, userTable, userColumn, userQualifier);
1775 
1776     verifyAllowed(noCheck, SUPERUSER, userTable, userColumn, userQualifier);
1777 
1778     // --------------------------------------
1779     // test family level multiple permissions
1780     AccessTestAction familyReadWrite = new AccessTestAction() {
1781       @Override
1782       public Void run() throws Exception {
1783         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ,
1784           Permission.Action.WRITE);
1785         return null;
1786       }
1787     };
1788 
1789     verifyAllowed(familyReadWrite, SUPERUSER, USER_OWNER, USER_CREATE, USER_RW);
1790     verifyDenied(familyReadWrite, USER_NONE, USER_RO);
1791 
1792     // --------------------------------------
1793     // check for wrong table region
1794     CheckPermissionsRequest checkRequest = CheckPermissionsRequest.newBuilder()
1795       .addPermission(AccessControlProtos.Permission.newBuilder()
1796           .setType(AccessControlProtos.Permission.Type.Table)
1797           .setTablePermission(
1798               AccessControlProtos.TablePermission.newBuilder()
1799                   .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE.getTableName()))
1800                   .addAction(AccessControlProtos.Permission.Action.CREATE))
1801       ).build();
1802     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1803     try {
1804       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1805       AccessControlService.BlockingInterface protocol =
1806         AccessControlService.newBlockingStub(channel);
1807       try {
1808         // but ask for TablePermissions for TEST_TABLE
1809         protocol.checkPermissions(null, checkRequest);
1810         fail("this should have thrown CoprocessorException");
1811       } catch (ServiceException ex) {
1812         // expected
1813       }
1814     } finally {
1815       acl.close();
1816     }
1817   }
1818 
1819   @Test
1820   public void testStopRegionServer() throws Exception {
1821     AccessTestAction action = new AccessTestAction() {
1822       @Override
1823       public Object run() throws Exception {
1824         ACCESS_CONTROLLER.preStopRegionServer(ObserverContext.createAndPrepare(RSCP_ENV, null));
1825         return null;
1826       }
1827     };
1828 
1829     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1830     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
1831   }
1832 
1833   @Test
1834   public void testRollWALWriterRequest() throws Exception {
1835     AccessTestAction action = new AccessTestAction() {
1836       @Override
1837       public Object run() throws Exception {
1838         ACCESS_CONTROLLER.preRollWALWriterRequest(ObserverContext.createAndPrepare(RSCP_ENV, null));
1839         return null;
1840       }
1841     };
1842 
1843     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1844     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
1845   }
1846 
1847   @Test
1848   public void testOpenRegion() throws Exception {
1849     AccessTestAction action = new AccessTestAction() {
1850       @Override
1851       public Object run() throws Exception {
1852         ACCESS_CONTROLLER.preOpen(ObserverContext.createAndPrepare(RCP_ENV, null));
1853         return null;
1854       }
1855     };
1856 
1857     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1858     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1859   }
1860 
1861   @Test
1862   public void testCloseRegion() throws Exception {
1863     AccessTestAction action = new AccessTestAction() {
1864       @Override
1865       public Object run() throws Exception {
1866         ACCESS_CONTROLLER.preClose(ObserverContext.createAndPrepare(RCP_ENV, null), false);
1867         return null;
1868       }
1869     };
1870 
1871     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1872     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1873   }
1874 
1875   @Test
1876   public void testSnapshot() throws Exception {
1877     AccessTestAction snapshotAction = new AccessTestAction() {
1878       @Override
1879       public Object run() throws Exception {
1880         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1881           null, null);
1882         return null;
1883       }
1884     };
1885 
1886     AccessTestAction deleteAction = new AccessTestAction() {
1887       @Override
1888       public Object run() throws Exception {
1889         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1890           null);
1891         return null;
1892       }
1893     };
1894 
1895     AccessTestAction restoreAction = new AccessTestAction() {
1896       @Override
1897       public Object run() throws Exception {
1898         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1899           null, null);
1900         return null;
1901       }
1902     };
1903 
1904     AccessTestAction cloneAction = new AccessTestAction() {
1905       @Override
1906       public Object run() throws Exception {
1907         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1908           null, null);
1909         return null;
1910       }
1911     };
1912 
1913     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN);
1914     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1915 
1916     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN);
1917     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1918 
1919     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN);
1920     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1921 
1922     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN);
1923     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1924   }
1925 
1926   @Test
1927   public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
1928     LOG.debug("Test for global authorization for a new registered RegionServer.");
1929     MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
1930 
1931     // Since each RegionServer running on different user, add global
1932     // permissions for the new user.
1933     String currentUser = User.getCurrent().getShortName();
1934     String activeUserForNewRs = currentUser + ".hfs." +
1935       hbaseCluster.getLiveRegionServerThreads().size();
1936     grantGlobal(TEST_UTIL, activeUserForNewRs,
1937       Permission.Action.ADMIN, Permission.Action.CREATE, Permission.Action.READ,
1938         Permission.Action.WRITE);
1939 
1940     final HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1941     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE2);
1942     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
1943     admin.createTable(htd);
1944     TEST_UTIL.waitUntilAllRegionsAssigned(TEST_TABLE2);
1945 
1946     // Starting a new RegionServer.
1947     JVMClusterUtil.RegionServerThread newRsThread = hbaseCluster
1948         .startRegionServer();
1949     final HRegionServer newRs = newRsThread.getRegionServer();
1950 
1951     // Move region to the new RegionServer.
1952     final HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE2);
1953     try {
1954       NavigableMap<HRegionInfo, ServerName> regions = table
1955           .getRegionLocations();
1956       final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet()
1957           .iterator().next();
1958 
1959       AccessTestAction moveAction = new AccessTestAction() {
1960         @Override
1961         public Object run() throws Exception {
1962           admin.move(firstRegion.getKey().getEncodedNameAsBytes(),
1963               Bytes.toBytes(newRs.getServerName().getServerName()));
1964           return null;
1965         }
1966       };
1967       SUPERUSER.runAs(moveAction);
1968 
1969       final int RETRIES_LIMIT = 10;
1970       int retries = 0;
1971       while (newRs.getOnlineRegions(TEST_TABLE2).size() < 1 && retries < RETRIES_LIMIT) {
1972         LOG.debug("Waiting for region to be opened. Already retried " + retries
1973             + " times.");
1974         try {
1975           Thread.sleep(1000);
1976         } catch (InterruptedException e) {
1977         }
1978         retries++;
1979         if (retries == RETRIES_LIMIT - 1) {
1980           fail("Retry exhaust for waiting region to be opened.");
1981         }
1982       }
1983       // Verify write permission for user "admin2" who has the global
1984       // permissions.
1985       AccessTestAction putAction = new AccessTestAction() {
1986         @Override
1987         public Object run() throws Exception {
1988           Put put = new Put(Bytes.toBytes("test"));
1989           put.add(TEST_FAMILY, Bytes.toBytes("qual"), Bytes.toBytes("value"));
1990           table.put(put);
1991           return null;
1992         }
1993       };
1994       USER_ADMIN.runAs(putAction);
1995     } finally {
1996       table.close();
1997     }
1998   }
1999 
2000   @Test
2001   public void testTableDescriptorsEnumeration() throws Exception {
2002     User TABLE_ADMIN = User.createUserForTesting(conf, "UserA", new String[0]);
2003 
2004     // Grant TABLE ADMIN privs
2005     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(),
2006       TEST_TABLE.getTableName(), null, null,
2007       Permission.Action.ADMIN);
2008 
2009     AccessTestAction listTablesAction = new AccessTestAction() {
2010       @Override
2011       public Object run() throws Exception {
2012         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2013         try {
2014           admin.listTables();
2015         } finally {
2016           admin.close();
2017         }
2018         return null;
2019       }
2020     };
2021 
2022     AccessTestAction getTableDescAction = new AccessTestAction() {
2023       @Override
2024       public Object run() throws Exception {
2025         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2026         try {
2027           admin.getTableDescriptor(TEST_TABLE.getTableName());
2028         } finally {
2029           admin.close();
2030         }
2031         return null;
2032       }
2033     };
2034 
2035     verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN);
2036     verifyDenied(listTablesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, TABLE_ADMIN);
2037 
2038     verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
2039     verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE);
2040   }
2041 
2042   @Test
2043   public void testTableDeletion() throws Exception {
2044     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
2045 
2046     // Grant TABLE ADMIN privs
2047     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(),
2048       TEST_TABLE.getTableName(), null, null,
2049       Permission.Action.ADMIN);
2050 
2051     AccessTestAction deleteTableAction = new AccessTestAction() {
2052       @Override
2053       public Object run() throws Exception {
2054         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2055         try {
2056           admin.disableTable(TEST_TABLE.getTableName());
2057           admin.deleteTable(TEST_TABLE.getTableName());
2058         } finally {
2059           admin.close();
2060         }
2061         return null;
2062       }
2063     };
2064 
2065     verifyDenied(deleteTableAction, USER_RW, USER_RO, USER_NONE);
2066     verifyAllowed(deleteTableAction, TABLE_ADMIN);
2067   }
2068 
2069   @Test
2070   public void testNamespaceUserGrant() throws Exception {
2071     AccessTestAction getAction = new AccessTestAction() {
2072       @Override
2073       public Object run() throws Exception {
2074         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2075         try {
2076           return t.get(new Get(TEST_ROW));
2077         } finally {
2078           t.close();
2079         }
2080       }
2081     };
2082 
2083     verifyDenied(getAction, USER_NONE);
2084 
2085     // Grant namespace READ to USER_NONE, this should supersede any table permissions
2086     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(),
2087       TEST_TABLE.getTableName().getNamespaceAsString(),
2088       Permission.Action.READ);
2089 
2090     // Now USER_NONE should be able to read also
2091     verifyAllowed(getAction, USER_NONE);
2092   }
2093 
2094   @Test
2095   public void testAccessControlClientGrantRevoke() throws Exception {
2096     // Create user for testing, who has no READ privileges by default.
2097     User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2098     AccessTestAction getAction = new AccessTestAction() {
2099       @Override
2100       public Object run() throws Exception {
2101         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2102         try {
2103           return t.get(new Get(TEST_ROW));
2104         } finally {
2105           t.close();
2106         }
2107       }
2108     };
2109 
2110     verifyDenied(getAction, testGrantRevoke);
2111 
2112     // Grant table READ permissions to testGrantRevoke.
2113     try {
2114       grantOnTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
2115           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
2116     } catch (Throwable e) {
2117       LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
2118     }
2119 
2120     // Now testGrantRevoke should be able to read also
2121     verifyAllowed(getAction, testGrantRevoke);
2122 
2123     // Revoke table READ permission to testGrantRevoke.
2124     try {
2125       revokeFromTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
2126           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
2127     } catch (Throwable e) {
2128       LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
2129     }
2130 
2131     // Now testGrantRevoke shouldn't be able read
2132     verifyDenied(getAction, testGrantRevoke);
2133   }
2134 
2135   @Test
2136   public void testAccessControlClientGlobalGrantRevoke() throws Exception {
2137     // Create user for testing, who has no READ privileges by default.
2138     User testGlobalGrantRevoke = User.createUserForTesting(conf,
2139       "testGlobalGrantRevoke", new String[0]);
2140     AccessTestAction getAction = new AccessTestAction() {
2141       @Override
2142       public Object run() throws Exception {
2143         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2144         try {
2145           return t.get(new Get(TEST_ROW));
2146         } finally {
2147           t.close();
2148         }
2149       }
2150     };
2151 
2152     verifyDenied(getAction, testGlobalGrantRevoke);
2153 
2154     // Grant table READ permissions to testGlobalGrantRevoke.
2155     try {
2156       grantGlobalUsingAccessControlClient(TEST_UTIL, conf, testGlobalGrantRevoke.getShortName(),
2157         Permission.Action.READ);
2158     } catch (Throwable e) {
2159       LOG.error("error during call of AccessControlClient.grant. ", e);
2160     }
2161 
2162     // Now testGlobalGrantRevoke should be able to read also
2163     verifyAllowed(getAction, testGlobalGrantRevoke);
2164 
2165     // Revoke table READ permission to testGlobalGrantRevoke.
2166     try {
2167       revokeGlobalUsingAccessControlClient(TEST_UTIL, conf, testGlobalGrantRevoke.getShortName(),
2168         Permission.Action.READ);
2169     } catch (Throwable e) {
2170       LOG.error("error during call of AccessControlClient.revoke ", e);
2171     }
2172 
2173     // Now testGlobalGrantRevoke shouldn't be able read
2174     verifyDenied(getAction, testGlobalGrantRevoke);
2175   }
2176 
2177   @Test
2178   public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
2179     // Create user for testing, who has no READ privileges by default.
2180     User testNS = User.createUserForTesting(conf, "testNS", new String[0]);
2181     AccessTestAction getAction = new AccessTestAction() {
2182       @Override
2183       public Object run() throws Exception {
2184         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2185         try {
2186           return t.get(new Get(TEST_ROW));
2187         } finally {
2188           t.close();
2189         }
2190       }
2191     };
2192 
2193     verifyDenied(getAction, testNS);
2194 
2195     // Grant namespace READ to testNS, this should supersede any table permissions
2196     try {
2197       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
2198           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
2199     } catch (Throwable e) {
2200       LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
2201     }
2202 
2203     // Now testNS should be able to read also
2204     verifyAllowed(getAction, testNS);
2205 
2206     // Revoke namespace READ to testNS, this should supersede any table permissions
2207     try {
2208       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
2209           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
2210     } catch (Throwable e) {
2211       LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
2212     }
2213 
2214     // Now testNS shouldn't be able read
2215     verifyDenied(getAction, testNS);
2216   }
2217 
2218 
2219   public static class PingCoprocessor extends PingService implements Coprocessor,
2220       CoprocessorService {
2221 
2222     @Override
2223     public void start(CoprocessorEnvironment env) throws IOException { }
2224 
2225     @Override
2226     public void stop(CoprocessorEnvironment env) throws IOException { }
2227 
2228     @Override
2229     public Service getService() {
2230       return this;
2231     }
2232 
2233     @Override
2234     public void ping(RpcController controller, PingRequest request,
2235         RpcCallback<PingResponse> callback) {
2236       callback.run(PingResponse.newBuilder().setPong("Pong!").build());
2237     }
2238 
2239     @Override
2240     public void count(RpcController controller, CountRequest request,
2241         RpcCallback<CountResponse> callback) {
2242       callback.run(CountResponse.newBuilder().build());
2243     }
2244 
2245     @Override
2246     public void increment(RpcController controller, IncrementCountRequest requet,
2247         RpcCallback<IncrementCountResponse> callback) {
2248       callback.run(IncrementCountResponse.newBuilder().build());
2249     }
2250 
2251     @Override
2252     public void hello(RpcController controller, HelloRequest request,
2253         RpcCallback<HelloResponse> callback) {
2254       callback.run(HelloResponse.newBuilder().setResponse("Hello!").build());
2255     }
2256 
2257     @Override
2258     public void noop(RpcController controller, NoopRequest request,
2259         RpcCallback<NoopResponse> callback) {
2260       callback.run(NoopResponse.newBuilder().build());
2261     }
2262   }
2263 
2264   @Test
2265   public void testCoprocessorExec() throws Exception {
2266     // Set up our ping endpoint service on all regions of our test table
2267     for (JVMClusterUtil.RegionServerThread thread:
2268         TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
2269       HRegionServer rs = thread.getRegionServer();
2270       for (HRegion region: rs.getOnlineRegions(TEST_TABLE.getTableName())) {
2271         region.getCoprocessorHost().load(PingCoprocessor.class,
2272           Coprocessor.PRIORITY_USER, conf);
2273       }
2274     }
2275 
2276     // Create users for testing, and grant EXEC privileges on our test table
2277     // only to user A
2278     User userA = User.createUserForTesting(conf, "UserA", new String[0]);
2279     User userB = User.createUserForTesting(conf, "UserB", new String[0]);
2280 
2281     grantOnTable(TEST_UTIL, userA.getShortName(),
2282       TEST_TABLE.getTableName(), null, null,
2283       Permission.Action.EXEC);
2284 
2285     // Create an action for invoking our test endpoint
2286     AccessTestAction execEndpointAction = new AccessTestAction() {
2287       @Override
2288       public Object run() throws Exception {
2289         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2290         try {
2291           BlockingRpcChannel service = t.coprocessorService(HConstants.EMPTY_BYTE_ARRAY);
2292           PingCoprocessor.newBlockingStub(service).noop(null, NoopRequest.newBuilder().build());
2293         } finally {
2294           t.close();
2295         }
2296         return null;
2297       }
2298     };
2299 
2300     // Verify that EXEC permission is checked correctly
2301     verifyDenied(execEndpointAction, userB);
2302     verifyAllowed(execEndpointAction, userA);
2303 
2304     // Now grant EXEC to the entire namespace to user B
2305     grantOnNamespace(TEST_UTIL, userB.getShortName(),
2306       TEST_TABLE.getTableName().getNamespaceAsString(),
2307       Permission.Action.EXEC);
2308 
2309     // User B should now be allowed also
2310     verifyAllowed(execEndpointAction, userA, userB);
2311   }
2312 
2313   @Test
2314   public void testReservedCellTags() throws Exception {
2315     AccessTestAction putWithReservedTag = new AccessTestAction() {
2316       @Override
2317       public Object run() throws Exception {
2318         HTable t = new HTable(conf, TEST_TABLE.getTableName());
2319         try {
2320           KeyValue kv = new KeyValue(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
2321             HConstants.LATEST_TIMESTAMP, HConstants.EMPTY_BYTE_ARRAY,
2322             new Tag[] { new Tag(AccessControlLists.ACL_TAG_TYPE,
2323               ProtobufUtil.toUsersAndPermissions(USER_OWNER.getShortName(),
2324                 new Permission(Permission.Action.READ)).toByteArray()) });
2325           t.put(new Put(TEST_ROW).add(kv));
2326         } finally {
2327           t.close();
2328         }
2329         return null;
2330       }
2331     };
2332 
2333     // Current user is superuser
2334     verifyAllowed(putWithReservedTag, User.getCurrent());
2335     // No other user should be allowed
2336     verifyDenied(putWithReservedTag, USER_OWNER, USER_ADMIN, USER_CREATE, USER_RW, USER_RO);
2337   }
2338 
2339   @Test
2340   public void testGetNamespacePermission() throws Exception {
2341     String namespace = "testNamespace";
2342     NamespaceDescriptor desc = NamespaceDescriptor.create(namespace).build();
2343     TEST_UTIL.getMiniHBaseCluster().getMaster().createNamespace(desc);
2344     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2345     try {
2346       List<UserPermission> namespacePermissions = AccessControlClient.getUserPermissions(conf,
2347       AccessControlLists.toNamespaceEntry(namespace));
2348       assertTrue(namespacePermissions != null);
2349       assertTrue(namespacePermissions.size() == 1);
2350     } catch (Throwable thw) {
2351       throw new HBaseException(thw);
2352     }
2353     TEST_UTIL.getMiniHBaseCluster().getMaster().deleteNamespace(namespace);
2354   }
2355 
2356   @Test
2357   public void testTruncatePerms() throws Exception {
2358     try {
2359       List<UserPermission> existingPerms = AccessControlClient.getUserPermissions(conf, TEST_TABLE
2360           .getTableName().getNameAsString());
2361       assertTrue(existingPerms != null);
2362       assertTrue(existingPerms.size() > 1);
2363       TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE.getTableName());
2364       TEST_UTIL.getHBaseAdmin().truncateTable(TEST_TABLE.getTableName(), true);
2365       List<UserPermission> perms = AccessControlClient.getUserPermissions(conf, TEST_TABLE
2366           .getTableName().getNameAsString());
2367       assertTrue(perms != null);
2368       assertEquals(existingPerms.size(), perms.size());
2369     } catch (Throwable e) {
2370       throw new HBaseIOException(e);
2371     }
2372   }
2373 
2374   private void verifyAnyCreate(AccessTestAction action) throws Exception {
2375     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_ADMIN_CF);
2376     verifyDenied(action, USER_NONE, USER_RO, USER_RW);
2377   }
2378 
2379   @Test
2380   public void testPrepareAndCleanBulkLoad() throws Exception {
2381     AccessTestAction prepareBulkLoadAction = new AccessTestAction() {
2382       @Override
2383       public Object run() throws Exception {
2384         ACCESS_CONTROLLER.prePrepareBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null), null);
2385         return null;
2386       }
2387     };
2388     AccessTestAction cleanupBulkLoadAction = new AccessTestAction() {
2389       @Override
2390       public Object run() throws Exception {
2391         ACCESS_CONTROLLER.preCleanupBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null), null);
2392         return null;
2393       }
2394     };
2395     verifyAnyCreate(prepareBulkLoadAction);
2396     verifyAnyCreate(cleanupBulkLoadAction);
2397   }
2398 
2399   @Test
2400   public void testReplicateLogEntries() throws Exception {
2401     AccessTestAction replicateLogEntriesAction = new AccessTestAction() {
2402       @Override
2403       public Object run() throws Exception {
2404         ACCESS_CONTROLLER.preReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2405           null, null);
2406         ACCESS_CONTROLLER.postReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2407           null, null);
2408         return null;
2409       }
2410     };
2411 
2412     verifyAllowed(replicateLogEntriesAction, SUPERUSER, USER_ADMIN);
2413     verifyDenied(replicateLogEntriesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
2414   }
2415 }