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