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