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