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