View Javadoc

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