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