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