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