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