View Javadoc

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