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