View Javadoc

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