View Javadoc

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