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.apache.hadoop.hbase.AuthUtil.toGroupEntry;
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertNotNull;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.security.PrivilegedAction;
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.List;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.hadoop.conf.Configuration;
40  import org.apache.hadoop.fs.FileStatus;
41  import org.apache.hadoop.fs.FileSystem;
42  import org.apache.hadoop.fs.Path;
43  import org.apache.hadoop.fs.permission.FsPermission;
44  import org.apache.hadoop.hbase.Coprocessor;
45  import org.apache.hadoop.hbase.CoprocessorEnvironment;
46  import org.apache.hadoop.hbase.HBaseIOException;
47  import org.apache.hadoop.hbase.HBaseTestingUtility;
48  import org.apache.hadoop.hbase.HColumnDescriptor;
49  import org.apache.hadoop.hbase.HConstants;
50  import org.apache.hadoop.hbase.HRegionInfo;
51  import org.apache.hadoop.hbase.HRegionLocation;
52  import org.apache.hadoop.hbase.HTableDescriptor;
53  import org.apache.hadoop.hbase.KeyValue;
54  import org.apache.hadoop.hbase.ProcedureInfo;
55  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
56  import org.apache.hadoop.hbase.security.Superusers;
57  import org.apache.hadoop.hbase.testclassification.LargeTests;
58  import org.apache.hadoop.hbase.MiniHBaseCluster;
59  import org.apache.hadoop.hbase.NamespaceDescriptor;
60  import org.apache.hadoop.hbase.ServerName;
61  import org.apache.hadoop.hbase.TableName;
62  import org.apache.hadoop.hbase.TableNotFoundException;
63  import org.apache.hadoop.hbase.client.Admin;
64  import org.apache.hadoop.hbase.client.Append;
65  import org.apache.hadoop.hbase.client.Connection;
66  import org.apache.hadoop.hbase.client.ConnectionFactory;
67  import org.apache.hadoop.hbase.client.Delete;
68  import org.apache.hadoop.hbase.client.Get;
69  import org.apache.hadoop.hbase.client.HTable;
70  import org.apache.hadoop.hbase.client.Increment;
71  import org.apache.hadoop.hbase.client.Put;
72  import org.apache.hadoop.hbase.client.RegionLocator;
73  import org.apache.hadoop.hbase.client.Result;
74  import org.apache.hadoop.hbase.client.ResultScanner;
75  import org.apache.hadoop.hbase.client.Scan;
76  import org.apache.hadoop.hbase.client.Table;
77  import org.apache.hadoop.hbase.client.security.SecurityCapability;
78  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
79  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
80  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
81  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
82  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
83  import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
84  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.CountRequest;
85  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.CountResponse;
86  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.HelloRequest;
87  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.HelloResponse;
88  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.IncrementCountRequest;
89  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.IncrementCountResponse;
90  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.NoopRequest;
91  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.NoopResponse;
92  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingRequest;
93  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingResponse;
94  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.PingProtos.PingService;
95  import org.apache.hadoop.hbase.exceptions.HBaseException;
96  import org.apache.hadoop.hbase.io.hfile.CacheConfig;
97  import org.apache.hadoop.hbase.io.hfile.HFile;
98  import org.apache.hadoop.hbase.io.hfile.HFileContext;
99  import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
100 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProcedureProtos;
101 import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
102 import org.apache.hadoop.hbase.master.HMaster;
103 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
104 import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
105 import org.apache.hadoop.hbase.master.procedure.TableProcedureInterface;
106 import org.apache.hadoop.hbase.procedure2.Procedure;
107 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
108 import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
109 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
110 import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
111 import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
112 import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
113 import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState;
114 import org.apache.hadoop.hbase.regionserver.HRegion;
115 import org.apache.hadoop.hbase.regionserver.HRegionServer;
116 import org.apache.hadoop.hbase.regionserver.Region;
117 import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
118 import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
119 import org.apache.hadoop.hbase.regionserver.ScanType;
120 import org.apache.hadoop.hbase.security.User;
121 import org.apache.hadoop.hbase.security.access.Permission.Action;
122 import org.apache.hadoop.hbase.util.Bytes;
123 import org.apache.hadoop.hbase.util.JVMClusterUtil;
124 import org.apache.log4j.Level;
125 import org.apache.log4j.Logger;
126 import org.junit.AfterClass;
127 import org.junit.BeforeClass;
128 import org.junit.Test;
129 import org.junit.experimental.categories.Category;
130 
131 import com.google.protobuf.BlockingRpcChannel;
132 import com.google.protobuf.RpcCallback;
133 import com.google.protobuf.RpcController;
134 import com.google.protobuf.Service;
135 import com.google.protobuf.ServiceException;
136 
137 /**
138  * Performs authorization checks for common operations, according to different
139  * levels of authorized users.
140  */
141 @Category(LargeTests.class)
142 public class TestAccessController extends SecureTestUtil {
143   private static final Log LOG = LogFactory.getLog(TestAccessController.class);
144 
145   static {
146     Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
147     Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
148     Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
149   }
150 
151   private static TableName TEST_TABLE = TableName.valueOf("testtable1");
152   private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
153   private static Configuration conf;
154 
155   /** The systemUserConnection created here is tied to the system user. In case, you are planning
156    * to create AccessTestAction, DON'T use this systemUserConnection as the 'doAs' user
157    * gets  eclipsed by the system user. */
158   private static Connection systemUserConnection;
159 
160 
161   // user with all permissions
162   private static User SUPERUSER;
163   // user granted with all global permission
164   private static User USER_ADMIN;
165   // user with rw permissions on column family.
166   private static User USER_RW;
167   // user with read-only permissions
168   private static User USER_RO;
169   // user is table owner. will have all permissions on table
170   private static User USER_OWNER;
171   // user with create table permissions alone
172   private static User USER_CREATE;
173   // user with no permissions
174   private static User USER_NONE;
175   // user with admin rights on the column family
176   private static User USER_ADMIN_CF;
177 
178   private static final String GROUP_ADMIN = "group_admin";
179   private static final String GROUP_CREATE = "group_create";
180   private static final String GROUP_READ = "group_read";
181   private static final String GROUP_WRITE = "group_write";
182 
183   private static User USER_GROUP_ADMIN;
184   private static User USER_GROUP_CREATE;
185   private static User USER_GROUP_READ;
186   private static User USER_GROUP_WRITE;
187 
188   // TODO: convert this test to cover the full matrix in
189   // https://hbase.apache.org/book/appendix_acl_matrix.html
190   // creating all Scope x Permission combinations
191 
192   private static TableName TEST_TABLE2 = TableName.valueOf("testtable2");
193   private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
194   private static byte[] TEST_QUALIFIER = Bytes.toBytes("q1");
195   private static byte[] TEST_ROW = Bytes.toBytes("r1");
196 
197   private static MasterCoprocessorEnvironment CP_ENV;
198   private static AccessController ACCESS_CONTROLLER;
199   private static RegionServerCoprocessorEnvironment RSCP_ENV;
200   private static RegionCoprocessorEnvironment RCP_ENV;
201 
202   @BeforeClass
203   public static void setupBeforeClass() throws Exception {
204     // setup configuration
205     conf = TEST_UTIL.getConfiguration();
206     // Up the handlers; this test needs more than usual.
207     conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
208     // Enable security
209     enableSecurity(conf);
210     // In this particular test case, we can't use SecureBulkLoadEndpoint because its doAs will fail
211     // to move a file for a random user
212     conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
213     // Verify enableSecurity sets up what we require
214     verifyConfiguration(conf);
215 
216     // Enable EXEC permission checking
217     conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true);
218 
219     TEST_UTIL.startMiniCluster();
220     MasterCoprocessorHost masterCpHost =
221       TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
222     masterCpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
223     ACCESS_CONTROLLER = (AccessController) masterCpHost.findCoprocessor(
224         AccessController.class.getName());
225     CP_ENV = masterCpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
226       Coprocessor.PRIORITY_HIGHEST, 1, conf);
227     RegionServerCoprocessorHost rsCpHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
228       .getRegionServerCoprocessorHost();
229     RSCP_ENV = rsCpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
230       Coprocessor.PRIORITY_HIGHEST, 1, conf);
231 
232     // Wait for the ACL table to become available
233     TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
234 
235     // create a set of test users
236     SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
237     USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
238     USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
239     USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
240     USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
241     USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
242     USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
243     USER_ADMIN_CF = User.createUserForTesting(conf, "col_family_admin", new String[0]);
244 
245     USER_GROUP_ADMIN =
246         User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN });
247     USER_GROUP_CREATE =
248         User.createUserForTesting(conf, "user_group_create", new String[] { GROUP_CREATE });
249     USER_GROUP_READ =
250         User.createUserForTesting(conf, "user_group_read", new String[] { GROUP_READ });
251     USER_GROUP_WRITE =
252         User.createUserForTesting(conf, "user_group_write", new String[] { GROUP_WRITE });
253 
254     systemUserConnection = TEST_UTIL.getConnection();
255     setUpTableAndUserPermissions();
256   }
257 
258   @AfterClass
259   public static void tearDownAfterClass() throws Exception {
260     cleanUp();
261     TEST_UTIL.shutdownMiniCluster();
262     int total = TableAuthManager.getTotalRefCount();
263     assertTrue("Unexpected reference count: " + total, total == 0);
264   }
265 
266   private static void setUpTableAndUserPermissions() throws Exception {
267     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
268     HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
269     hcd.setMaxVersions(100);
270     htd.addFamily(hcd);
271     htd.setOwner(USER_OWNER);
272     createTable(TEST_UTIL, htd, new byte[][] { Bytes.toBytes("s") });
273     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
274 
275     Region region = TEST_UTIL.getHBaseCluster().getRegions(TEST_TABLE).get(0);
276     RegionCoprocessorHost rcpHost = region.getCoprocessorHost();
277     RCP_ENV = rcpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
278       Coprocessor.PRIORITY_HIGHEST, 1, conf);
279 
280     // Set up initial grants
281 
282     grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(),
283       Permission.Action.ADMIN,
284       Permission.Action.CREATE,
285       Permission.Action.READ,
286       Permission.Action.WRITE);
287 
288     grantOnTable(TEST_UTIL, USER_RW.getShortName(),
289       TEST_TABLE, TEST_FAMILY, null,
290       Permission.Action.READ,
291       Permission.Action.WRITE);
292 
293     // USER_CREATE is USER_RW plus CREATE permissions
294     grantOnTable(TEST_UTIL, USER_CREATE.getShortName(),
295       TEST_TABLE, null, null,
296       Permission.Action.CREATE,
297       Permission.Action.READ,
298       Permission.Action.WRITE);
299 
300     grantOnTable(TEST_UTIL, USER_RO.getShortName(),
301       TEST_TABLE, TEST_FAMILY, null,
302       Permission.Action.READ);
303 
304     grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(),
305       TEST_TABLE, TEST_FAMILY,
306       null, Permission.Action.ADMIN, Permission.Action.CREATE);
307 
308     grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN);
309     grantGlobal(TEST_UTIL, toGroupEntry(GROUP_CREATE), Permission.Action.CREATE);
310     grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ);
311     grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE);
312 
313     assertEquals(5, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size());
314     try {
315       assertEquals(5, AccessControlClient.getUserPermissions(systemUserConnection,
316           TEST_TABLE.toString()).size());
317     } catch (Throwable e) {
318       LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
319     }
320   }
321 
322   private static void cleanUp() throws Exception {
323     // Clean the _acl_ table
324     try {
325       deleteTable(TEST_UTIL, TEST_TABLE);
326     } catch (TableNotFoundException ex) {
327       // Test deleted the table, no problem
328       LOG.info("Test deleted table " + TEST_TABLE);
329     }
330     // Verify all table/namespace permissions are erased
331     assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size());
332     assertEquals(
333         0,
334         AccessControlLists.getNamespacePermissions(conf,
335             TEST_TABLE.getNamespaceAsString()).size());
336   }
337 
338   @Test (timeout=180000)
339   public void testUnauthorizedShutdown() throws Exception {
340     AccessTestAction action = new AccessTestAction() {
341       @Override public Object run() throws Exception {
342         HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
343         master.shutdown();
344         return null;
345       }
346     };
347     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
348         USER_GROUP_WRITE, USER_GROUP_CREATE);
349   }
350 
351   @Test (timeout=180000)
352   public void testUnauthorizedStopMaster() throws Exception {
353     AccessTestAction action = new AccessTestAction() {
354       @Override public Object run() throws Exception {
355         HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
356         master.stopMaster();
357         return null;
358       }
359     };
360 
361     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
362         USER_GROUP_WRITE, USER_GROUP_CREATE);
363   }
364 
365   @Test (timeout=180000)
366   public void testSecurityCapabilities() throws Exception {
367     List<SecurityCapability> capabilities = TEST_UTIL.getConnection().getAdmin()
368       .getSecurityCapabilities();
369     assertTrue("AUTHORIZATION capability is missing",
370       capabilities.contains(SecurityCapability.AUTHORIZATION));
371     assertTrue("CELL_AUTHORIZATION capability is missing",
372       capabilities.contains(SecurityCapability.CELL_AUTHORIZATION));
373   }
374 
375   @Test (timeout=180000)
376   public void testTableCreate() throws Exception {
377     AccessTestAction createTable = new AccessTestAction() {
378       @Override
379       public Object run() throws Exception {
380         HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testnewtable"));
381         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
382         ACCESS_CONTROLLER.preCreateTable(ObserverContext.createAndPrepare(CP_ENV, null), htd, null);
383         return null;
384       }
385     };
386 
387     // verify that superuser can create tables
388     verifyAllowed(createTable, SUPERUSER, USER_ADMIN, USER_GROUP_CREATE);
389 
390     // all others should be denied
391     verifyDenied(createTable, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_ADMIN,
392       USER_GROUP_READ, USER_GROUP_WRITE);
393   }
394 
395   @Test (timeout=180000)
396   public void testTableModify() throws Exception {
397     AccessTestAction modifyTable = new AccessTestAction() {
398       @Override
399       public Object run() throws Exception {
400         HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
401         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
402         htd.addFamily(new HColumnDescriptor("fam_" + User.getCurrent().getShortName()));
403         ACCESS_CONTROLLER.preModifyTable(ObserverContext.createAndPrepare(CP_ENV, null),
404             TEST_TABLE, htd);
405         return null;
406       }
407     };
408 
409     verifyAllowed(modifyTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
410       USER_GROUP_ADMIN);
411     verifyDenied(modifyTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
412   }
413 
414   @Test (timeout=180000)
415   public void testTableDelete() throws Exception {
416     AccessTestAction deleteTable = new AccessTestAction() {
417       @Override
418       public Object run() throws Exception {
419         ACCESS_CONTROLLER
420             .preDeleteTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE);
421         return null;
422       }
423     };
424 
425     verifyAllowed(deleteTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
426       USER_GROUP_ADMIN);
427     verifyDenied(deleteTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
428   }
429 
430   @Test (timeout=180000)
431   public void testTableTruncate() throws Exception {
432     AccessTestAction truncateTable = new AccessTestAction() {
433       @Override
434       public Object run() throws Exception {
435         ACCESS_CONTROLLER
436             .preTruncateTable(ObserverContext.createAndPrepare(CP_ENV, null),
437                 TEST_TABLE);
438         return null;
439       }
440     };
441 
442     verifyAllowed(truncateTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
443       USER_GROUP_ADMIN);
444     verifyDenied(truncateTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
445   }
446 
447   @Test (timeout=180000)
448   public void testAddColumn() throws Exception {
449     final HColumnDescriptor hcd = new HColumnDescriptor("fam_new");
450     AccessTestAction action = new AccessTestAction() {
451       @Override
452       public Object run() throws Exception {
453         ACCESS_CONTROLLER.preAddColumn(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE,
454             hcd);
455         return null;
456       }
457     };
458 
459     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
460       USER_GROUP_ADMIN);
461     verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
462   }
463 
464   @Test (timeout=180000)
465   public void testModifyColumn() throws Exception {
466     final HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
467     hcd.setMaxVersions(10);
468     AccessTestAction action = new AccessTestAction() {
469       @Override
470       public Object run() throws Exception {
471         ACCESS_CONTROLLER.preModifyColumn(ObserverContext.createAndPrepare(CP_ENV, null),
472             TEST_TABLE, hcd);
473         return null;
474       }
475     };
476 
477     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_ADMIN_CF,
478       USER_GROUP_CREATE, USER_GROUP_ADMIN);
479     verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
480   }
481 
482   @Test (timeout=180000)
483   public void testDeleteColumn() throws Exception {
484     AccessTestAction action = new AccessTestAction() {
485       @Override
486       public Object run() throws Exception {
487         ACCESS_CONTROLLER.preDeleteColumn(ObserverContext.createAndPrepare(CP_ENV, null),
488             TEST_TABLE, TEST_FAMILY);
489         return null;
490       }
491     };
492 
493     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_ADMIN_CF,
494         USER_GROUP_CREATE, USER_GROUP_ADMIN);
495     verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
496   }
497 
498   @Test (timeout=180000)
499   public void testTableDisable() throws Exception {
500     AccessTestAction disableTable = new AccessTestAction() {
501       @Override
502       public Object run() throws Exception {
503         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
504           TEST_TABLE);
505         return null;
506       }
507     };
508 
509     AccessTestAction disableAclTable = new AccessTestAction() {
510       @Override
511       public Object run() throws Exception {
512         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
513             AccessControlLists.ACL_TABLE_NAME);
514         return null;
515       }
516     };
517 
518     verifyAllowed(disableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
519       USER_GROUP_ADMIN);
520     verifyDenied(disableTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
521 
522     // No user should be allowed to disable _acl_ table
523     verifyDenied(disableAclTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
524       USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_WRITE);
525   }
526 
527   @Test (timeout=180000)
528   public void testTableEnable() throws Exception {
529     AccessTestAction enableTable = new AccessTestAction() {
530       @Override
531       public Object run() throws Exception {
532         ACCESS_CONTROLLER
533             .preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE);
534         return null;
535       }
536     };
537 
538     verifyAllowed(enableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
539       USER_GROUP_ADMIN);
540     verifyDenied(enableTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
541   }
542 
543   public static class TestTableDDLProcedure extends Procedure<MasterProcedureEnv>
544   implements TableProcedureInterface {
545     private TableName tableName;
546 
547     public TestTableDDLProcedure() {
548     }
549 
550     public TestTableDDLProcedure(final MasterProcedureEnv env, final TableName tableName)
551         throws IOException {
552       this.tableName = tableName;
553       this.setTimeout(180000); // Timeout in 3 minutes
554       this.setOwner(env.getRequestUser().getUGI().getShortUserName());
555     }
556 
557     @Override
558     public TableName getTableName() {
559       return tableName;
560     }
561 
562     @Override
563     public TableOperationType getTableOperationType() {
564       return null;
565     }
566 
567     @Override
568     protected boolean abort(MasterProcedureEnv env) {
569       return true;
570     }
571 
572     @Override
573     protected void serializeStateData(OutputStream stream) throws IOException {
574       TestProcedureProtos.TestTableDDLStateData.Builder testTableDDLMsg =
575           TestProcedureProtos.TestTableDDLStateData.newBuilder()
576           .setTableName(tableName.getNameAsString());
577       testTableDDLMsg.build().writeDelimitedTo(stream);
578     }
579 
580     @Override
581     protected void deserializeStateData(InputStream stream) throws IOException {
582       TestProcedureProtos.TestTableDDLStateData testTableDDLMsg =
583           TestProcedureProtos.TestTableDDLStateData.parseDelimitedFrom(stream);
584       tableName = TableName.valueOf(testTableDDLMsg.getTableName());
585     }
586 
587     @Override
588     protected Procedure[] execute(MasterProcedureEnv env) throws ProcedureYieldException,
589         InterruptedException {
590       // Not letting the procedure to complete until timed out
591       setState(ProcedureState.WAITING_TIMEOUT);
592       return null;
593     }
594 
595     @Override
596     protected void rollback(MasterProcedureEnv env) throws IOException, InterruptedException {
597     }
598   }
599 
600   @Test
601   public void testAbortProcedure() throws Exception {
602     final TableName tableName = TableName.valueOf("testAbortProcedure");
603     final ProcedureExecutor<MasterProcedureEnv> procExec =
604         TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
605     Procedure proc = new TestTableDDLProcedure(procExec.getEnvironment(), tableName);
606     proc.setOwner(USER_OWNER.getShortName());
607     final long procId = procExec.submitProcedure(proc);
608 
609     AccessTestAction abortProcedureAction = new AccessTestAction() {
610       @Override
611       public Object run() throws Exception {
612         ACCESS_CONTROLLER
613         .preAbortProcedure(ObserverContext.createAndPrepare(CP_ENV, null), procExec, procId);
614        return null;
615       }
616     };
617 
618     verifyAllowed(abortProcedureAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
619     verifyAllowed(abortProcedureAction, USER_OWNER);
620     verifyDenied(
621       abortProcedureAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
622   }
623 
624   @Test
625   public void testListProcedures() throws Exception {
626     final TableName tableName = TableName.valueOf("testAbortProcedure");
627     final ProcedureExecutor<MasterProcedureEnv> procExec =
628         TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
629     Procedure proc = new TestTableDDLProcedure(procExec.getEnvironment(), tableName);
630     proc.setOwner(USER_OWNER.getShortName());
631     final long procId = procExec.submitProcedure(proc);
632     final List<ProcedureInfo> procInfoList = procExec.listProcedures();
633 
634     AccessTestAction listProceduresAction = new AccessTestAction() {
635       @Override
636       public Object run() throws Exception {
637         List<ProcedureInfo> procInfoListClone = new ArrayList<ProcedureInfo>(procInfoList.size());
638         for(ProcedureInfo pi : procInfoList) {
639           procInfoListClone.add(pi.clone());
640         }
641         ACCESS_CONTROLLER
642         .postListProcedures(ObserverContext.createAndPrepare(CP_ENV, null), procInfoListClone);
643        return null;
644       }
645     };
646 
647     verifyAllowed(listProceduresAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
648     verifyAllowed(listProceduresAction, USER_OWNER);
649     verifyIfNull(
650       listProceduresAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
651   }
652 
653   @Test (timeout=180000)
654   public void testMove() throws Exception {
655     List<HRegionLocation> regions;
656     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
657       regions = locator.getAllRegionLocations();
658     }
659     HRegionLocation location = regions.get(0);
660     final HRegionInfo hri = location.getRegionInfo();
661     final ServerName server = location.getServerName();
662     AccessTestAction action = new AccessTestAction() {
663       @Override
664       public Object run() throws Exception {
665         ACCESS_CONTROLLER.preMove(ObserverContext.createAndPrepare(CP_ENV, null),
666             hri, server, server);
667         return null;
668       }
669     };
670 
671     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
672     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
673       USER_GROUP_WRITE, USER_GROUP_CREATE);
674   }
675 
676   @Test (timeout=180000)
677   public void testAssign() throws Exception {
678     List<HRegionLocation> regions;
679     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
680       regions = locator.getAllRegionLocations();
681     }
682     HRegionLocation location = regions.get(0);
683     final HRegionInfo hri = location.getRegionInfo();
684     AccessTestAction action = new AccessTestAction() {
685       @Override
686       public Object run() throws Exception {
687         ACCESS_CONTROLLER.preAssign(ObserverContext.createAndPrepare(CP_ENV, null), hri);
688         return null;
689       }
690     };
691 
692     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
693     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
694       USER_GROUP_WRITE, USER_GROUP_CREATE);
695   }
696 
697   @Test (timeout=180000)
698   public void testUnassign() throws Exception {
699     List<HRegionLocation> regions;
700     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
701       regions = locator.getAllRegionLocations();
702     }
703     HRegionLocation location = regions.get(0);
704     final HRegionInfo hri = location.getRegionInfo();
705     AccessTestAction action = new AccessTestAction() {
706       @Override
707       public Object run() throws Exception {
708         ACCESS_CONTROLLER.preUnassign(ObserverContext.createAndPrepare(CP_ENV, null), hri, false);
709         return null;
710       }
711     };
712 
713     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
714     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
715       USER_GROUP_WRITE, USER_GROUP_CREATE);
716   }
717 
718   @Test (timeout=180000)
719   public void testRegionOffline() throws Exception {
720     List<HRegionLocation> regions;
721     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
722       regions = locator.getAllRegionLocations();
723     }
724     HRegionLocation location = regions.get(0);
725     final HRegionInfo hri = location.getRegionInfo();
726     AccessTestAction action = new AccessTestAction() {
727       @Override
728       public Object run() throws Exception {
729         ACCESS_CONTROLLER.preRegionOffline(ObserverContext.createAndPrepare(CP_ENV, null), hri);
730         return null;
731       }
732     };
733 
734     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
735     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
736       USER_GROUP_WRITE, USER_GROUP_CREATE);
737   }
738 
739   @Test (timeout=180000)
740   public void testSetSplitOrMergeEnabled() throws Exception {
741     AccessTestAction action = new AccessTestAction() {
742       @Override
743       public Object run() throws Exception {
744         ACCESS_CONTROLLER.preSetSplitOrMergeEnabled(ObserverContext.createAndPrepare(CP_ENV, null),
745           true, Admin.MasterSwitchType.MERGE);
746         return null;
747       }
748     };
749 
750     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
751     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
752       USER_GROUP_WRITE, USER_GROUP_CREATE);
753   }
754 
755   @Test (timeout=180000)
756   public void testBalance() throws Exception {
757     AccessTestAction action = new AccessTestAction() {
758       @Override
759       public Object run() throws Exception {
760         ACCESS_CONTROLLER.preBalance(ObserverContext.createAndPrepare(CP_ENV, null));
761         return null;
762       }
763     };
764 
765     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
766     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
767       USER_GROUP_WRITE, USER_GROUP_CREATE);
768   }
769 
770   @Test (timeout=180000)
771   public void testBalanceSwitch() throws Exception {
772     AccessTestAction action = new AccessTestAction() {
773       @Override
774       public Object run() throws Exception {
775         ACCESS_CONTROLLER.preBalanceSwitch(ObserverContext.createAndPrepare(CP_ENV, null), true);
776         return null;
777       }
778     };
779 
780     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
781     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
782       USER_GROUP_WRITE, USER_GROUP_CREATE);
783   }
784 
785   @Test (timeout=180000)
786   public void testShutdown() throws Exception {
787     AccessTestAction action = new AccessTestAction() {
788       @Override
789       public Object run() throws Exception {
790         ACCESS_CONTROLLER.preShutdown(ObserverContext.createAndPrepare(CP_ENV, null));
791         return null;
792       }
793     };
794 
795     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
796     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
797       USER_GROUP_WRITE, USER_GROUP_CREATE);
798   }
799 
800   @Test (timeout=180000)
801   public void testStopMaster() throws Exception {
802     AccessTestAction action = new AccessTestAction() {
803       @Override
804       public Object run() throws Exception {
805         ACCESS_CONTROLLER.preStopMaster(ObserverContext.createAndPrepare(CP_ENV, null));
806         return null;
807       }
808     };
809 
810     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
811     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
812       USER_GROUP_WRITE, USER_GROUP_CREATE);
813   }
814 
815   private void verifyWrite(AccessTestAction action) throws Exception {
816     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
817       USER_GROUP_WRITE);
818     verifyDenied(action, USER_NONE, USER_RO, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_CREATE);
819   }
820 
821   @Test (timeout=180000)
822   public void testSplit() throws Exception {
823     AccessTestAction action = new AccessTestAction() {
824       @Override
825       public Object run() throws Exception {
826         ACCESS_CONTROLLER.preSplit(ObserverContext.createAndPrepare(RCP_ENV, null));
827         return null;
828       }
829     };
830 
831     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
832     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
833       USER_GROUP_WRITE, USER_GROUP_CREATE);
834   }
835 
836   @Test (timeout=180000)
837   public void testSplitWithSplitRow() throws Exception {
838     AccessTestAction action = new AccessTestAction() {
839       @Override
840       public Object run() throws Exception {
841         ACCESS_CONTROLLER.preSplit(
842             ObserverContext.createAndPrepare(RCP_ENV, null),
843             TEST_ROW);
844         return null;
845       }
846     };
847 
848     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
849     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
850         USER_GROUP_WRITE, USER_GROUP_CREATE);
851   }
852 
853   @Test (timeout=180000)
854   public void testMergeRegions() throws Exception {
855     final TableName tname = TableName.valueOf("testMergeRegions");
856     createTestTable(tname);
857     try {
858       final List<HRegion> regions = TEST_UTIL.getHBaseCluster().findRegionsForTable(tname);
859       assertTrue("not enough regions: " + regions.size(), regions.size() >= 2);
860 
861       AccessTestAction action = new AccessTestAction() {
862         @Override
863         public Object run() throws Exception {
864           ACCESS_CONTROLLER.preMerge(ObserverContext.createAndPrepare(RSCP_ENV, null),
865             regions.get(0), regions.get(1));
866           return null;
867         }
868       };
869 
870       verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
871       verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
872         USER_GROUP_WRITE, USER_GROUP_CREATE);
873     } finally {
874       deleteTable(TEST_UTIL, tname);
875     }
876   }
877 
878   @Test (timeout=180000)
879   public void testFlush() throws Exception {
880     AccessTestAction action = new AccessTestAction() {
881       @Override
882       public Object run() throws Exception {
883         ACCESS_CONTROLLER.preFlush(ObserverContext.createAndPrepare(RCP_ENV, null));
884         return null;
885       }
886     };
887 
888     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_GROUP_CREATE,
889       USER_GROUP_ADMIN);
890     verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
891   }
892 
893   @Test (timeout=180000)
894   public void testCompact() throws Exception {
895     AccessTestAction action = new AccessTestAction() {
896       @Override
897       public Object run() throws Exception {
898         ACCESS_CONTROLLER.preCompact(ObserverContext.createAndPrepare(RCP_ENV, null), null, null,
899           ScanType.COMPACT_RETAIN_DELETES);
900         return null;
901       }
902     };
903 
904     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_GROUP_CREATE,
905       USER_GROUP_ADMIN);
906     verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
907   }
908 
909   private void verifyRead(AccessTestAction action) throws Exception {
910     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
911       USER_GROUP_READ);
912     verifyDenied(action, USER_NONE, USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_WRITE);
913   }
914 
915   private void verifyReadWrite(AccessTestAction action) throws Exception {
916     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
917     verifyDenied(action, USER_NONE, USER_RO, USER_GROUP_ADMIN, USER_GROUP_CREATE, USER_GROUP_READ,
918         USER_GROUP_WRITE);
919   }
920 
921   @Test (timeout=180000)
922   public void testRead() throws Exception {
923     // get action
924     AccessTestAction getAction = new AccessTestAction() {
925       @Override
926       public Object run() throws Exception {
927         Get g = new Get(TEST_ROW);
928         g.addFamily(TEST_FAMILY);
929         try(Connection conn = ConnectionFactory.createConnection(conf);
930             Table t = conn.getTable(TEST_TABLE)) {
931           t.get(g);
932         }
933         return null;
934       }
935     };
936     verifyRead(getAction);
937 
938     // action for scanning
939     AccessTestAction scanAction = new AccessTestAction() {
940       @Override
941       public Object run() throws Exception {
942         Scan s = new Scan();
943         s.addFamily(TEST_FAMILY);
944 
945         try(Connection conn = ConnectionFactory.createConnection(conf);
946             Table table = conn.getTable(TEST_TABLE)) {
947           ResultScanner scanner = table.getScanner(s);
948           try {
949             for (Result r = scanner.next(); r != null; r = scanner.next()) {
950               // do nothing
951             }
952           } finally {
953             scanner.close();
954           }
955         }
956         return null;
957       }
958     };
959     verifyRead(scanAction);
960   }
961 
962   @Test (timeout=180000)
963   // test put, delete, increment
964   public void testWrite() throws Exception {
965     // put action
966     AccessTestAction putAction = new AccessTestAction() {
967       @Override
968       public Object run() throws Exception {
969         Put p = new Put(TEST_ROW);
970         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
971         try(Connection conn = ConnectionFactory.createConnection(conf);
972             Table t = conn.getTable(TEST_TABLE)) {
973           t.put(p);
974         }
975         return null;
976       }
977     };
978     verifyWrite(putAction);
979 
980     // delete action
981     AccessTestAction deleteAction = new AccessTestAction() {
982       @Override
983       public Object run() throws Exception {
984         Delete d = new Delete(TEST_ROW);
985         d.deleteFamily(TEST_FAMILY);
986         try(Connection conn = ConnectionFactory.createConnection(conf);
987             Table t = conn.getTable(TEST_TABLE)) {
988           t.delete(d);
989         }
990         return null;
991       }
992     };
993     verifyWrite(deleteAction);
994 
995     // increment action
996     AccessTestAction incrementAction = new AccessTestAction() {
997       @Override
998       public Object run() throws Exception {
999         Increment inc = new Increment(TEST_ROW);
1000         inc.addColumn(TEST_FAMILY, TEST_QUALIFIER, 1);
1001         try(Connection conn = ConnectionFactory.createConnection(conf);
1002             Table t = conn.getTable(TEST_TABLE);) {
1003           t.increment(inc);
1004         }
1005         return null;
1006       }
1007     };
1008     verifyWrite(incrementAction);
1009   }
1010 
1011   @Test (timeout=180000)
1012   public void testReadWrite() throws Exception {
1013     // action for checkAndDelete
1014     AccessTestAction checkAndDeleteAction = new AccessTestAction() {
1015       @Override
1016       public Object run() throws Exception {
1017         Delete d = new Delete(TEST_ROW);
1018         d.deleteFamily(TEST_FAMILY);
1019         try(Connection conn = ConnectionFactory.createConnection(conf);
1020             Table t = conn.getTable(TEST_TABLE);) {
1021           t.checkAndDelete(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
1022               Bytes.toBytes("test_value"), d);
1023         }
1024         return null;
1025       }
1026     };
1027     verifyReadWrite(checkAndDeleteAction);
1028 
1029     // action for checkAndPut()
1030     AccessTestAction checkAndPut = new AccessTestAction() {
1031       @Override
1032       public Object run() throws Exception {
1033         Put p = new Put(TEST_ROW);
1034         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
1035         try(Connection conn = ConnectionFactory.createConnection(conf);
1036             Table t = conn.getTable(TEST_TABLE);) {
1037           t.checkAndPut(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
1038               Bytes.toBytes("test_value"), p);
1039         }
1040         return null;
1041       }
1042     };
1043     verifyReadWrite(checkAndPut);
1044   }
1045 
1046   @Test (timeout=180000)
1047   public void testBulkLoad() throws Exception {
1048     try {
1049       FileSystem fs = TEST_UTIL.getTestFileSystem();
1050       final Path dir = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoad");
1051       fs.mkdirs(dir);
1052       // need to make it globally writable
1053       // so users creating HFiles have write permissions
1054       fs.setPermission(dir, FsPermission.valueOf("-rwxrwxrwx"));
1055 
1056       AccessTestAction bulkLoadAction = new AccessTestAction() {
1057         @Override
1058         public Object run() throws Exception {
1059           int numRows = 3;
1060 
1061           // Making the assumption that the test table won't split between the range
1062           byte[][][] hfileRanges = { { { (byte) 0 }, { (byte) 9 } } };
1063 
1064           Path bulkLoadBasePath = new Path(dir, new Path(User.getCurrent().getName()));
1065           new BulkLoadHelper(bulkLoadBasePath).bulkLoadHFile(TEST_TABLE, TEST_FAMILY,
1066             TEST_QUALIFIER, hfileRanges, numRows);
1067 
1068           return null;
1069         }
1070       };
1071 
1072       // User performing bulk loads must have privilege to read table metadata
1073       // (ADMIN or CREATE)
1074       verifyAllowed(bulkLoadAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
1075         USER_GROUP_CREATE);
1076       verifyDenied(bulkLoadAction, USER_RW, USER_NONE, USER_RO, USER_GROUP_READ, USER_GROUP_WRITE,
1077         USER_GROUP_ADMIN);
1078     } finally {
1079       // Reinit after the bulk upload
1080       TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE);
1081       TEST_UTIL.getHBaseAdmin().enableTable(TEST_TABLE);
1082     }
1083   }
1084 
1085   public class BulkLoadHelper {
1086     private final FileSystem fs;
1087     private final Path loadPath;
1088     private final Configuration conf;
1089 
1090     public BulkLoadHelper(Path loadPath) throws IOException {
1091       fs = TEST_UTIL.getTestFileSystem();
1092       conf = TEST_UTIL.getConfiguration();
1093       loadPath = loadPath.makeQualified(fs);
1094       this.loadPath = loadPath;
1095     }
1096 
1097     private void createHFile(Path path,
1098         byte[] family, byte[] qualifier,
1099         byte[] startKey, byte[] endKey, int numRows) throws IOException {
1100 
1101       HFile.Writer writer = null;
1102       long now = System.currentTimeMillis();
1103       try {
1104         HFileContext context = new HFileContextBuilder().build();
1105         writer = HFile.getWriterFactory(conf, new CacheConfig(conf))
1106             .withPath(fs, path)
1107             .withFileContext(context)
1108             .create();
1109         // subtract 2 since numRows doesn't include boundary keys
1110         for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, true, numRows-2)) {
1111           KeyValue kv = new KeyValue(key, family, qualifier, now, key);
1112           writer.append(kv);
1113         }
1114       } finally {
1115         if(writer != null)
1116           writer.close();
1117       }
1118     }
1119 
1120     private void bulkLoadHFile(
1121         TableName tableName,
1122         byte[] family,
1123         byte[] qualifier,
1124         byte[][][] hfileRanges,
1125         int numRowsPerRange) throws Exception {
1126 
1127       Path familyDir = new Path(loadPath, Bytes.toString(family));
1128       fs.mkdirs(familyDir);
1129       int hfileIdx = 0;
1130       for (byte[][] range : hfileRanges) {
1131         byte[] from = range[0];
1132         byte[] to = range[1];
1133         createHFile(new Path(familyDir, "hfile_"+(hfileIdx++)),
1134             family, qualifier, from, to, numRowsPerRange);
1135       }
1136       //set global read so RegionServer can move it
1137       setPermission(loadPath, FsPermission.valueOf("-rwxrwxrwx"));
1138 
1139       try (Connection conn = ConnectionFactory.createConnection(conf);
1140            HTable table = (HTable)conn.getTable(tableName)) {
1141         TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1142         LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
1143         loader.doBulkLoad(loadPath, table);
1144       }
1145     }
1146 
1147     public void setPermission(Path dir, FsPermission perm) throws IOException {
1148       if(!fs.getFileStatus(dir).isDirectory()) {
1149         fs.setPermission(dir,perm);
1150       }
1151       else {
1152         for(FileStatus el : fs.listStatus(dir)) {
1153           fs.setPermission(el.getPath(), perm);
1154           setPermission(el.getPath() , perm);
1155         }
1156       }
1157     }
1158   }
1159 
1160   @Test (timeout=180000)
1161   public void testAppend() throws Exception {
1162 
1163     AccessTestAction appendAction = new AccessTestAction() {
1164       @Override
1165       public Object run() throws Exception {
1166         byte[] row = TEST_ROW;
1167         byte[] qualifier = TEST_QUALIFIER;
1168         Put put = new Put(row);
1169         put.add(TEST_FAMILY, qualifier, Bytes.toBytes(1));
1170         Append append = new Append(row);
1171         append.add(TEST_FAMILY, qualifier, Bytes.toBytes(2));
1172         try(Connection conn = ConnectionFactory.createConnection(conf);
1173             Table t = conn.getTable(TEST_TABLE)) {
1174           t.put(put);
1175           t.append(append);
1176         }
1177         return null;
1178       }
1179     };
1180 
1181     verifyAllowed(appendAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
1182       USER_GROUP_WRITE);
1183     verifyDenied(appendAction, USER_RO, USER_NONE, USER_GROUP_CREATE, USER_GROUP_READ,
1184       USER_GROUP_ADMIN);
1185   }
1186 
1187   @Test (timeout=180000)
1188   public void testGrantRevoke() throws Exception {
1189     AccessTestAction grantAction = new AccessTestAction() {
1190       @Override
1191       public Object run() throws Exception {
1192         try(Connection conn = ConnectionFactory.createConnection(conf);
1193             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1194           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1195           AccessControlService.BlockingInterface protocol =
1196             AccessControlService.newBlockingStub(service);
1197           ProtobufUtil.grant(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null, false,
1198             Action.READ);
1199         }
1200         return null;
1201       }
1202     };
1203 
1204     AccessTestAction revokeAction = new AccessTestAction() {
1205       @Override
1206       public Object run() throws Exception {
1207         try(Connection conn = ConnectionFactory.createConnection(conf);
1208             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1209           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1210           AccessControlService.BlockingInterface protocol =
1211             AccessControlService.newBlockingStub(service);
1212           ProtobufUtil.revoke(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1213             Action.READ);
1214         }
1215         return null;
1216       }
1217     };
1218 
1219     AccessTestAction getTablePermissionsAction = new AccessTestAction() {
1220       @Override
1221       public Object run() throws Exception {
1222         try(Connection conn = ConnectionFactory.createConnection(conf);
1223             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)){
1224           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1225           AccessControlService.BlockingInterface protocol =
1226               AccessControlService.newBlockingStub(service);
1227           ProtobufUtil.getUserPermissions(null, protocol, TEST_TABLE);
1228         }
1229         return null;
1230       }
1231     };
1232 
1233     AccessTestAction getGlobalPermissionsAction = new AccessTestAction() {
1234       @Override
1235       public Object run() throws Exception {
1236         try(Connection conn = ConnectionFactory.createConnection(conf);
1237             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1238           BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1239           AccessControlService.BlockingInterface protocol =
1240             AccessControlService.newBlockingStub(service);
1241           ProtobufUtil.getUserPermissions(null, protocol);
1242         }
1243         return null;
1244       }
1245     };
1246 
1247     verifyAllowed(grantAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1248     verifyDenied(grantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1249         USER_GROUP_WRITE, USER_GROUP_CREATE);
1250     try {
1251       verifyAllowed(revokeAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1252       verifyDenied(revokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1253         USER_GROUP_WRITE, USER_GROUP_CREATE);
1254 
1255       verifyAllowed(getTablePermissionsAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1256       verifyDenied(getTablePermissionsAction, USER_CREATE, USER_RW, USER_RO, USER_NONE,
1257         USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1258 
1259       verifyAllowed(getGlobalPermissionsAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1260       verifyDenied(getGlobalPermissionsAction, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
1261         USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1262     } finally {
1263       // Cleanup, Grant the revoked permission back to the user
1264       grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1265           Permission.Action.READ);
1266     }
1267   }
1268 
1269   @Test (timeout=180000)
1270   public void testPostGrantRevoke() throws Exception {
1271     final TableName tableName =
1272         TableName.valueOf("TempTable");
1273     final byte[] family1 = Bytes.toBytes("f1");
1274     final byte[] family2 = Bytes.toBytes("f2");
1275     final byte[] qualifier = Bytes.toBytes("q");
1276 
1277     // create table
1278     Admin admin = TEST_UTIL.getHBaseAdmin();
1279     if (admin.tableExists(tableName)) {
1280       deleteTable(TEST_UTIL, tableName);
1281     }
1282     HTableDescriptor htd = new HTableDescriptor(tableName);
1283     htd.addFamily(new HColumnDescriptor(family1));
1284     htd.addFamily(new HColumnDescriptor(family2));
1285     createTable(TEST_UTIL, htd);
1286     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1287     try {
1288       // create temp users
1289       User tblUser =
1290           User.createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]);
1291       User gblUser =
1292           User.createUserForTesting(TEST_UTIL.getConfiguration(), "gbluser", new String[0]);
1293 
1294       // prepare actions:
1295       AccessTestAction putActionAll = new AccessTestAction() {
1296         @Override
1297         public Object run() throws Exception {
1298           Put p = new Put(Bytes.toBytes("a"));
1299           p.add(family1, qualifier, Bytes.toBytes("v1"));
1300           p.add(family2, qualifier, Bytes.toBytes("v2"));
1301           try (Connection conn = ConnectionFactory.createConnection(conf);
1302               Table t = conn.getTable(tableName);) {
1303             t.put(p);
1304           }
1305           return null;
1306         }
1307       };
1308 
1309       AccessTestAction putAction1 = new AccessTestAction() {
1310         @Override
1311         public Object run() throws Exception {
1312           Put p = new Put(Bytes.toBytes("a"));
1313           p.add(family1, qualifier, Bytes.toBytes("v1"));
1314 
1315           try (Connection conn = ConnectionFactory.createConnection(conf);
1316               Table t = conn.getTable(tableName)) {
1317             t.put(p);
1318           }
1319           return null;
1320         }
1321       };
1322 
1323       AccessTestAction putAction2 = new AccessTestAction() {
1324         @Override
1325         public Object run() throws Exception {
1326           Put p = new Put(Bytes.toBytes("a"));
1327           p.add(family2, qualifier, Bytes.toBytes("v2"));
1328           try (Connection conn = ConnectionFactory.createConnection(conf);
1329               Table t = conn.getTable(tableName);) {
1330             t.put(p);
1331           }
1332           return null;
1333         }
1334       };
1335 
1336       AccessTestAction getActionAll = new AccessTestAction() {
1337         @Override
1338         public Object run() throws Exception {
1339           Get g = new Get(TEST_ROW);
1340           g.addFamily(family1);
1341           g.addFamily(family2);
1342           try (Connection conn = ConnectionFactory.createConnection(conf);
1343               Table t = conn.getTable(tableName);) {
1344             t.get(g);
1345           }
1346           return null;
1347         }
1348       };
1349 
1350       AccessTestAction getAction1 = new AccessTestAction() {
1351         @Override
1352         public Object run() throws Exception {
1353           Get g = new Get(TEST_ROW);
1354           g.addFamily(family1);
1355           try (Connection conn = ConnectionFactory.createConnection(conf);
1356               Table t = conn.getTable(tableName)) {
1357             t.get(g);
1358           }
1359           return null;
1360         }
1361       };
1362 
1363       AccessTestAction getAction2 = new AccessTestAction() {
1364         @Override
1365         public Object run() throws Exception {
1366           Get g = new Get(TEST_ROW);
1367           g.addFamily(family2);
1368           try (Connection conn = ConnectionFactory.createConnection(conf);
1369               Table t = conn.getTable(tableName)) {
1370             t.get(g);
1371           }
1372           return null;
1373         }
1374       };
1375 
1376       AccessTestAction deleteActionAll = new AccessTestAction() {
1377         @Override
1378         public Object run() throws Exception {
1379           Delete d = new Delete(TEST_ROW);
1380           d.deleteFamily(family1);
1381           d.deleteFamily(family2);
1382           try (Connection conn = ConnectionFactory.createConnection(conf);
1383               Table t = conn.getTable(tableName)) {
1384             t.delete(d);
1385           }
1386           return null;
1387         }
1388       };
1389 
1390       AccessTestAction deleteAction1 = new AccessTestAction() {
1391         @Override
1392         public Object run() throws Exception {
1393           Delete d = new Delete(TEST_ROW);
1394           d.deleteFamily(family1);
1395           try (Connection conn = ConnectionFactory.createConnection(conf);
1396               Table t = conn.getTable(tableName)) {
1397             t.delete(d);
1398           }
1399           return null;
1400         }
1401       };
1402 
1403       AccessTestAction deleteAction2 = new AccessTestAction() {
1404         @Override
1405         public Object run() throws Exception {
1406           Delete d = new Delete(TEST_ROW);
1407           d.deleteFamily(family2);
1408           try (Connection conn = ConnectionFactory.createConnection(conf);
1409               Table t = conn.getTable(tableName)) {
1410             t.delete(d);
1411           }
1412           return null;
1413         }
1414       };
1415 
1416       // initial check:
1417       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1418       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1419       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1420 
1421       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1422       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1423       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1424 
1425       // grant table read permission
1426       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1427       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null, Permission.Action.READ);
1428 
1429       // check
1430       verifyAllowed(tblUser, getActionAll, getAction1, getAction2);
1431       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1432       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1433 
1434       verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1435       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1436       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1437 
1438       // grant table write permission while revoking read permissions
1439       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1440       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null,
1441         Permission.Action.WRITE);
1442 
1443       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1444       verifyAllowed(tblUser, putActionAll, putAction1, putAction2);
1445       verifyAllowed(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1446 
1447       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1448       verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1449       verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1450 
1451       // revoke table permissions
1452       revokeGlobal(TEST_UTIL, gblUser.getShortName());
1453       revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null);
1454 
1455       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1456       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1457       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1458 
1459       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1460       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1461       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1462 
1463       // grant column family read permission
1464       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1465       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family1, null,
1466         Permission.Action.READ);
1467 
1468       // Access should be denied for family2
1469       verifyAllowed(tblUser, getActionAll, getAction1);
1470       verifyDenied(tblUser, getAction2);
1471       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1472       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1473 
1474       verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1475       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1476       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1477 
1478       // grant column family write permission
1479       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1480       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null,
1481         Permission.Action.WRITE);
1482 
1483       // READ from family1, WRITE to family2 are allowed
1484       verifyAllowed(tblUser, getActionAll, getAction1);
1485       verifyAllowed(tblUser, putAction2, deleteAction2);
1486       verifyDenied(tblUser, getAction2);
1487       verifyDenied(tblUser, putActionAll, putAction1);
1488       verifyDenied(tblUser, deleteActionAll, deleteAction1);
1489 
1490       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1491       verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1492       verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1493 
1494       // revoke column family permission
1495       revokeGlobal(TEST_UTIL, gblUser.getShortName());
1496       revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null);
1497 
1498       // Revoke on family2 should not have impact on family1 permissions
1499       verifyAllowed(tblUser, getActionAll, getAction1);
1500       verifyDenied(tblUser, getAction2);
1501       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1502       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1503 
1504       // Should not have access as global permissions are completely revoked
1505       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1506       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1507       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1508     } finally {
1509       // delete table
1510       deleteTable(TEST_UTIL, tableName);
1511     }
1512   }
1513 
1514   private boolean hasFoundUserPermission(List<UserPermission> userPermissions,
1515                                          List<UserPermission> perms) {
1516     return perms.containsAll(userPermissions);
1517   }
1518 
1519   private boolean hasFoundUserPermission(UserPermission userPermission, List<UserPermission> perms) {
1520     return perms.contains(userPermission);
1521   }
1522 
1523   @Test (timeout=180000)
1524   public void testPostGrantRevokeAtQualifierLevel() throws Exception {
1525     final TableName tableName =
1526         TableName.valueOf("testGrantRevokeAtQualifierLevel");
1527     final byte[] family1 = Bytes.toBytes("f1");
1528     final byte[] family2 = Bytes.toBytes("f2");
1529     final byte[] qualifier = Bytes.toBytes("q");
1530 
1531     // create table
1532     Admin admin = TEST_UTIL.getHBaseAdmin();
1533     if (admin.tableExists(tableName)) {
1534       deleteTable(TEST_UTIL, tableName);
1535     }
1536     HTableDescriptor htd = new HTableDescriptor(tableName);
1537     htd.addFamily(new HColumnDescriptor(family1));
1538     htd.addFamily(new HColumnDescriptor(family2));
1539     createTable(TEST_UTIL, htd);
1540     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1541     try {
1542       // create temp users
1543       User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1544 
1545       AccessTestAction getQualifierAction = new AccessTestAction() {
1546         @Override
1547         public Object run() throws Exception {
1548           Get g = new Get(TEST_ROW);
1549           g.addColumn(family1, qualifier);
1550           try (Connection conn = ConnectionFactory.createConnection(conf);
1551               Table t = conn.getTable(tableName)) {
1552             t.get(g);
1553           }
1554           return null;
1555         }
1556       };
1557 
1558       AccessTestAction putQualifierAction = new AccessTestAction() {
1559         @Override
1560         public Object run() throws Exception {
1561           Put p = new Put(TEST_ROW);
1562           p.add(family1, qualifier, Bytes.toBytes("v1"));
1563           try (Connection conn = ConnectionFactory.createConnection(conf);
1564               Table t = conn.getTable(tableName)) {
1565             t.put(p);
1566           }
1567           return null;
1568         }
1569       };
1570 
1571       AccessTestAction deleteQualifierAction = new AccessTestAction() {
1572         @Override
1573         public Object run() throws Exception {
1574           Delete d = new Delete(TEST_ROW);
1575           d.deleteColumn(family1, qualifier);
1576           // d.deleteFamily(family1);
1577           try (Connection conn = ConnectionFactory.createConnection(conf);
1578               Table t = conn.getTable(tableName)) {
1579             t.delete(d);
1580           }
1581           return null;
1582         }
1583       };
1584 
1585       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, null);
1586 
1587       verifyDenied(user, getQualifierAction);
1588       verifyDenied(user, putQualifierAction);
1589       verifyDenied(user, deleteQualifierAction);
1590 
1591       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1592         Permission.Action.READ);
1593 
1594       verifyAllowed(user, getQualifierAction);
1595       verifyDenied(user, putQualifierAction);
1596       verifyDenied(user, deleteQualifierAction);
1597 
1598       // only grant write permission
1599       // TODO: comment this portion after HBASE-3583
1600       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1601         Permission.Action.WRITE);
1602 
1603       verifyDenied(user, getQualifierAction);
1604       verifyAllowed(user, putQualifierAction);
1605       verifyAllowed(user, deleteQualifierAction);
1606 
1607       // grant both read and write permission
1608       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1609         Permission.Action.READ, Permission.Action.WRITE);
1610 
1611       verifyAllowed(user, getQualifierAction);
1612       verifyAllowed(user, putQualifierAction);
1613       verifyAllowed(user, deleteQualifierAction);
1614 
1615       // revoke family level permission won't impact column level
1616       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier);
1617 
1618       verifyDenied(user, getQualifierAction);
1619       verifyDenied(user, putQualifierAction);
1620       verifyDenied(user, deleteQualifierAction);
1621     } finally {
1622       // delete table
1623       deleteTable(TEST_UTIL, tableName);
1624     }
1625   }
1626 
1627   @Test (timeout=180000)
1628   public void testPermissionList() throws Exception {
1629     final TableName tableName =
1630         TableName.valueOf("testPermissionList");
1631     final byte[] family1 = Bytes.toBytes("f1");
1632     final byte[] family2 = Bytes.toBytes("f2");
1633     final byte[] qualifier = Bytes.toBytes("q");
1634 
1635     // create table
1636     Admin admin = TEST_UTIL.getHBaseAdmin();
1637     if (admin.tableExists(tableName)) {
1638       deleteTable(TEST_UTIL, tableName);
1639     }
1640     HTableDescriptor htd = new HTableDescriptor(tableName);
1641     htd.addFamily(new HColumnDescriptor(family1));
1642     htd.addFamily(new HColumnDescriptor(family2));
1643     htd.setOwner(USER_OWNER);
1644     createTable(TEST_UTIL, htd);
1645     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1646     try {
1647       List<UserPermission> perms;
1648       Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1649       try {
1650         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1651         AccessControlService.BlockingInterface protocol =
1652             AccessControlService.newBlockingStub(service);
1653         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1654       } finally {
1655         acl.close();
1656       }
1657 
1658       UserPermission ownerperm =
1659           new UserPermission(Bytes.toBytes(USER_OWNER.getName()), tableName, null, Action.values());
1660       assertTrue("Owner should have all permissions on table",
1661         hasFoundUserPermission(ownerperm, perms));
1662 
1663       User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1664       byte[] userName = Bytes.toBytes(user.getShortName());
1665 
1666       UserPermission up =
1667           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.READ);
1668       assertFalse("User should not be granted permission: " + up.toString(),
1669         hasFoundUserPermission(up, perms));
1670 
1671       // grant read permission
1672       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1673         Permission.Action.READ);
1674 
1675       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1676       try {
1677         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1678         AccessControlService.BlockingInterface protocol =
1679             AccessControlService.newBlockingStub(service);
1680         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1681       } finally {
1682         acl.close();
1683       }
1684 
1685       UserPermission upToVerify =
1686           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.READ);
1687       assertTrue("User should be granted permission: " + upToVerify.toString(),
1688         hasFoundUserPermission(upToVerify, perms));
1689 
1690       upToVerify =
1691           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.WRITE);
1692       assertFalse("User should not be granted permission: " + upToVerify.toString(),
1693         hasFoundUserPermission(upToVerify, perms));
1694 
1695       // grant read+write
1696       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1697         Permission.Action.WRITE, Permission.Action.READ);
1698 
1699       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1700       try {
1701         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1702         AccessControlService.BlockingInterface protocol =
1703             AccessControlService.newBlockingStub(service);
1704         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1705       } finally {
1706         acl.close();
1707       }
1708 
1709       upToVerify =
1710           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.WRITE,
1711               Permission.Action.READ);
1712       assertTrue("User should be granted permission: " + upToVerify.toString(),
1713         hasFoundUserPermission(upToVerify, perms));
1714 
1715       // revoke
1716       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1717         Permission.Action.WRITE, Permission.Action.READ);
1718 
1719       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1720       try {
1721         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1722         AccessControlService.BlockingInterface protocol =
1723             AccessControlService.newBlockingStub(service);
1724         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1725       } finally {
1726         acl.close();
1727       }
1728 
1729       assertFalse("User should not be granted permission: " + upToVerify.toString(),
1730         hasFoundUserPermission(upToVerify, perms));
1731 
1732       // disable table before modification
1733       admin.disableTable(tableName);
1734 
1735       User newOwner = User.createUserForTesting(conf, "new_owner", new String[] {});
1736       htd.setOwner(newOwner);
1737       admin.modifyTable(tableName, htd);
1738 
1739       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1740       try {
1741         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1742         AccessControlService.BlockingInterface protocol =
1743             AccessControlService.newBlockingStub(service);
1744         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1745       } finally {
1746         acl.close();
1747       }
1748 
1749       UserPermission newOwnerperm =
1750           new UserPermission(Bytes.toBytes(newOwner.getName()), tableName, null, Action.values());
1751       assertTrue("New owner should have all permissions on table",
1752         hasFoundUserPermission(newOwnerperm, perms));
1753     } finally {
1754       // delete table
1755       deleteTable(TEST_UTIL, tableName);
1756     }
1757   }
1758 
1759   @Test (timeout=180000)
1760   public void testGlobalPermissionList() throws Exception {
1761     List<UserPermission> perms;
1762     Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1763     try {
1764       BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1765       AccessControlService.BlockingInterface protocol =
1766         AccessControlService.newBlockingStub(service);
1767       perms = ProtobufUtil.getUserPermissions(null, protocol);
1768     } finally {
1769       acl.close();
1770     }
1771     List<UserPermission> adminPerms = new ArrayList<UserPermission>();
1772     adminPerms.add(new UserPermission(Bytes.toBytes(USER_ADMIN.getShortName()),
1773       AccessControlLists.ACL_TABLE_NAME, null, null, Bytes.toBytes("ACRW")));
1774     List<String> superUsers = Superusers.getSuperUsers();
1775     for(String user: superUsers) {
1776       adminPerms.add(new UserPermission(Bytes.toBytes(user), AccessControlLists.ACL_TABLE_NAME,
1777           null, null, Action.values()));
1778     }
1779     assertTrue("Only super users, global users and user admin has permission on table hbase:acl " +
1780         "per setup", perms.size() == 5 + superUsers.size() &&
1781         hasFoundUserPermission(adminPerms, perms));
1782   }
1783 
1784   /** global operations */
1785   private void verifyGlobal(AccessTestAction action) throws Exception {
1786     verifyAllowed(action, SUPERUSER);
1787 
1788     verifyDenied(action, USER_CREATE, USER_RW, USER_NONE, USER_RO);
1789   }
1790 
1791   @Test (timeout=180000)
1792   public void testCheckPermissions() throws Exception {
1793     // --------------------------------------
1794     // test global permissions
1795     AccessTestAction globalAdmin = new AccessTestAction() {
1796       @Override
1797       public Void run() throws Exception {
1798         checkGlobalPerms(TEST_UTIL, Permission.Action.ADMIN);
1799         return null;
1800       }
1801     };
1802     // verify that only superuser can admin
1803     verifyGlobal(globalAdmin);
1804 
1805     // --------------------------------------
1806     // test multiple permissions
1807     AccessTestAction globalReadWrite = new AccessTestAction() {
1808       @Override
1809       public Void run() throws Exception {
1810         checkGlobalPerms(TEST_UTIL, Permission.Action.READ, Permission.Action.WRITE);
1811         return null;
1812       }
1813     };
1814 
1815     verifyGlobal(globalReadWrite);
1816 
1817     // --------------------------------------
1818     // table/column/qualifier level permissions
1819     final byte[] TEST_Q1 = Bytes.toBytes("q1");
1820     final byte[] TEST_Q2 = Bytes.toBytes("q2");
1821 
1822     User userTable = User.createUserForTesting(conf, "user_check_perms_table", new String[0]);
1823     User userColumn = User.createUserForTesting(conf, "user_check_perms_family", new String[0]);
1824     User userQualifier = User.createUserForTesting(conf, "user_check_perms_q", new String[0]);
1825 
1826     grantOnTable(TEST_UTIL, userTable.getShortName(),
1827       TEST_TABLE, null, null,
1828       Permission.Action.READ);
1829     grantOnTable(TEST_UTIL, userColumn.getShortName(),
1830       TEST_TABLE, TEST_FAMILY, null,
1831       Permission.Action.READ);
1832     grantOnTable(TEST_UTIL, userQualifier.getShortName(),
1833       TEST_TABLE, TEST_FAMILY, TEST_Q1,
1834       Permission.Action.READ);
1835 
1836     try {
1837       AccessTestAction tableRead = new AccessTestAction() {
1838         @Override
1839         public Void run() throws Exception {
1840           checkTablePerms(TEST_UTIL, TEST_TABLE, null, null, Permission.Action.READ);
1841           return null;
1842         }
1843       };
1844 
1845       AccessTestAction columnRead = new AccessTestAction() {
1846         @Override
1847         public Void run() throws Exception {
1848           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ);
1849           return null;
1850         }
1851       };
1852 
1853       AccessTestAction qualifierRead = new AccessTestAction() {
1854         @Override
1855         public Void run() throws Exception {
1856           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1857           return null;
1858         }
1859       };
1860 
1861       AccessTestAction multiQualifierRead = new AccessTestAction() {
1862         @Override
1863         public Void run() throws Exception {
1864           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] {
1865               new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ),
1866               new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q2, Permission.Action.READ), });
1867           return null;
1868         }
1869       };
1870 
1871       AccessTestAction globalAndTableRead = new AccessTestAction() {
1872         @Override
1873         public Void run() throws Exception {
1874           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] {
1875               new Permission(Permission.Action.READ),
1876               new TablePermission(TEST_TABLE, null, (byte[]) null, Permission.Action.READ), });
1877           return null;
1878         }
1879       };
1880 
1881       AccessTestAction noCheck = new AccessTestAction() {
1882         @Override
1883         public Void run() throws Exception {
1884           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[0]);
1885           return null;
1886         }
1887       };
1888 
1889       verifyAllowed(tableRead, SUPERUSER, userTable);
1890       verifyDenied(tableRead, userColumn, userQualifier);
1891 
1892       verifyAllowed(columnRead, SUPERUSER, userTable, userColumn);
1893       verifyDenied(columnRead, userQualifier);
1894 
1895       verifyAllowed(qualifierRead, SUPERUSER, userTable, userColumn, userQualifier);
1896 
1897       verifyAllowed(multiQualifierRead, SUPERUSER, userTable, userColumn);
1898       verifyDenied(multiQualifierRead, userQualifier);
1899 
1900       verifyAllowed(globalAndTableRead, SUPERUSER);
1901       verifyDenied(globalAndTableRead, userTable, userColumn, userQualifier);
1902 
1903       verifyAllowed(noCheck, SUPERUSER, userTable, userColumn, userQualifier);
1904 
1905       // --------------------------------------
1906       // test family level multiple permissions
1907       AccessTestAction familyReadWrite = new AccessTestAction() {
1908         @Override
1909         public Void run() throws Exception {
1910           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ,
1911             Permission.Action.WRITE);
1912           return null;
1913         }
1914       };
1915 
1916       verifyAllowed(familyReadWrite, SUPERUSER, USER_OWNER, USER_CREATE, USER_RW);
1917       verifyDenied(familyReadWrite, USER_NONE, USER_RO);
1918 
1919       // --------------------------------------
1920       // check for wrong table region
1921       CheckPermissionsRequest checkRequest =
1922           CheckPermissionsRequest
1923               .newBuilder()
1924               .addPermission(
1925                 AccessControlProtos.Permission
1926                     .newBuilder()
1927                     .setType(AccessControlProtos.Permission.Type.Table)
1928                     .setTablePermission(
1929                       AccessControlProtos.TablePermission.newBuilder()
1930                           .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE))
1931                           .addAction(AccessControlProtos.Permission.Action.CREATE))).build();
1932       Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1933       try {
1934         BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1935         AccessControlService.BlockingInterface protocol =
1936             AccessControlService.newBlockingStub(channel);
1937         try {
1938           // but ask for TablePermissions for TEST_TABLE
1939           protocol.checkPermissions(null, checkRequest);
1940           fail("this should have thrown CoprocessorException");
1941         } catch (ServiceException ex) {
1942           // expected
1943         }
1944       } finally {
1945         acl.close();
1946       }
1947 
1948     } finally {
1949       revokeFromTable(TEST_UTIL, userTable.getShortName(), TEST_TABLE, null, null,
1950         Permission.Action.READ);
1951       revokeFromTable(TEST_UTIL, userColumn.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1952         Permission.Action.READ);
1953       revokeFromTable(TEST_UTIL, userQualifier.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_Q1,
1954         Permission.Action.READ);
1955     }
1956   }
1957 
1958   @Test (timeout=180000)
1959   public void testStopRegionServer() throws Exception {
1960     AccessTestAction action = new AccessTestAction() {
1961       @Override
1962       public Object run() throws Exception {
1963         ACCESS_CONTROLLER.preStopRegionServer(ObserverContext.createAndPrepare(RSCP_ENV, null));
1964         return null;
1965       }
1966     };
1967 
1968     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1969     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1970       USER_GROUP_WRITE, USER_GROUP_CREATE);
1971   }
1972 
1973   @Test (timeout=180000)
1974   public void testRollWALWriterRequest() throws Exception {
1975     AccessTestAction action = new AccessTestAction() {
1976       @Override
1977       public Object run() throws Exception {
1978         ACCESS_CONTROLLER.preRollWALWriterRequest(ObserverContext.createAndPrepare(RSCP_ENV, null));
1979         return null;
1980       }
1981     };
1982 
1983     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1984     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1985       USER_GROUP_WRITE, USER_GROUP_CREATE);
1986   }
1987 
1988   @Test (timeout=180000)
1989   public void testOpenRegion() throws Exception {
1990     AccessTestAction action = new AccessTestAction() {
1991       @Override
1992       public Object run() throws Exception {
1993         ACCESS_CONTROLLER.preOpen(ObserverContext.createAndPrepare(RCP_ENV, null));
1994         return null;
1995       }
1996     };
1997 
1998     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1999     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2000       USER_GROUP_READ, USER_GROUP_WRITE);
2001   }
2002 
2003   @Test (timeout=180000)
2004   public void testCloseRegion() throws Exception {
2005     AccessTestAction action = new AccessTestAction() {
2006       @Override
2007       public Object run() throws Exception {
2008         ACCESS_CONTROLLER.preClose(ObserverContext.createAndPrepare(RCP_ENV, null), false);
2009         return null;
2010       }
2011     };
2012 
2013     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2014     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2015       USER_GROUP_READ, USER_GROUP_WRITE);
2016   }
2017 
2018   @Test (timeout=180000)
2019   public void testSnapshot() throws Exception {
2020     Admin admin = TEST_UTIL.getHBaseAdmin();
2021     final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE);
2022     SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
2023     builder.setName(TEST_TABLE.getNameAsString() + "-snapshot");
2024     builder.setTable(TEST_TABLE.getNameAsString());
2025     final SnapshotDescription snapshot = builder.build();
2026     AccessTestAction snapshotAction = new AccessTestAction() {
2027       @Override
2028       public Object run() throws Exception {
2029         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2030           snapshot, htd);
2031         return null;
2032       }
2033     };
2034 
2035     AccessTestAction deleteAction = new AccessTestAction() {
2036       @Override
2037       public Object run() throws Exception {
2038         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2039           snapshot);
2040         return null;
2041       }
2042     };
2043 
2044     AccessTestAction restoreAction = new AccessTestAction() {
2045       @Override
2046       public Object run() throws Exception {
2047         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2048           snapshot, htd);
2049         return null;
2050       }
2051     };
2052 
2053     AccessTestAction cloneAction = new AccessTestAction() {
2054       @Override
2055       public Object run() throws Exception {
2056         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2057           snapshot, null);
2058         return null;
2059       }
2060     };
2061 
2062     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2063     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2064       USER_GROUP_WRITE, USER_GROUP_CREATE);
2065 
2066     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2067     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2068       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2069 
2070     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2071     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2072       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2073 
2074     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2075     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2076       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2077   }
2078 
2079   @Test (timeout=180000)
2080   public void testSnapshotWithOwner() throws Exception {
2081     Admin admin = TEST_UTIL.getHBaseAdmin();
2082     final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE);
2083     SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
2084     builder.setName(TEST_TABLE.getNameAsString() + "-snapshot");
2085     builder.setTable(TEST_TABLE.getNameAsString());
2086     builder.setOwner(USER_OWNER.getName());
2087     final SnapshotDescription snapshot = builder.build();
2088     AccessTestAction snapshotAction = new AccessTestAction() {
2089       @Override
2090       public Object run() throws Exception {
2091         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2092           snapshot, htd);
2093         return null;
2094       }
2095     };
2096     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2097     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2098       USER_GROUP_WRITE, USER_GROUP_CREATE);
2099 
2100     AccessTestAction deleteAction = new AccessTestAction() {
2101       @Override
2102       public Object run() throws Exception {
2103         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2104           snapshot);
2105         return null;
2106       }
2107     };
2108     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2109     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2110       USER_GROUP_WRITE, USER_GROUP_CREATE);
2111 
2112     AccessTestAction restoreAction = new AccessTestAction() {
2113       @Override
2114       public Object run() throws Exception {
2115         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2116           snapshot, htd);
2117         return null;
2118       }
2119     };
2120     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2121     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2122       USER_GROUP_WRITE, USER_GROUP_CREATE);
2123 
2124     AccessTestAction cloneAction = new AccessTestAction() {
2125       @Override
2126       public Object run() throws Exception {
2127         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2128           snapshot, htd);
2129         return null;
2130       }
2131     };
2132     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER);
2133     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2134       USER_GROUP_WRITE, USER_GROUP_CREATE);
2135   }
2136 
2137   @Test (timeout=180000)
2138   public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
2139     LOG.debug("Test for global authorization for a new registered RegionServer.");
2140     MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
2141 
2142     final Admin admin = TEST_UTIL.getHBaseAdmin();
2143     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE2);
2144     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
2145     createTable(TEST_UTIL, htd);
2146     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2147 
2148     // Starting a new RegionServer.
2149     JVMClusterUtil.RegionServerThread newRsThread = hbaseCluster
2150         .startRegionServer();
2151     final HRegionServer newRs = newRsThread.getRegionServer();
2152 
2153     // Move region to the new RegionServer.
2154     List<HRegionLocation> regions;
2155     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE2)) {
2156       regions = locator.getAllRegionLocations();
2157     }
2158     HRegionLocation location = regions.get(0);
2159     final HRegionInfo hri = location.getRegionInfo();
2160     final ServerName server = location.getServerName();
2161     try (HTable table = (HTable) systemUserConnection.getTable(TEST_TABLE2)) {
2162       AccessTestAction moveAction = new AccessTestAction() {
2163         @Override
2164         public Object run() throws Exception {
2165           admin.move(hri.getEncodedNameAsBytes(),
2166             Bytes.toBytes(newRs.getServerName().getServerName()));
2167           return null;
2168         }
2169       };
2170       SUPERUSER.runAs(moveAction);
2171 
2172       final int RETRIES_LIMIT = 10;
2173       int retries = 0;
2174       while (newRs.getOnlineRegions(TEST_TABLE2).size() < 1 && retries < RETRIES_LIMIT) {
2175         LOG.debug("Waiting for region to be opened. Already retried " + retries
2176             + " times.");
2177         try {
2178           Thread.sleep(1000);
2179         } catch (InterruptedException e) {
2180         }
2181         retries++;
2182         if (retries == RETRIES_LIMIT - 1) {
2183           fail("Retry exhaust for waiting region to be opened.");
2184         }
2185       }
2186       // Verify write permission for user "admin2" who has the global
2187       // permissions.
2188       AccessTestAction putAction = new AccessTestAction() {
2189         @Override
2190         public Object run() throws Exception {
2191           Put put = new Put(Bytes.toBytes("test"));
2192           put.add(TEST_FAMILY, Bytes.toBytes("qual"), Bytes.toBytes("value"));
2193           table.put(put);
2194           return null;
2195         }
2196       };
2197       USER_ADMIN.runAs(putAction);
2198     }
2199   }
2200 
2201   @Test (timeout=180000)
2202   public void testTableDescriptorsEnumeration() throws Exception {
2203     User TABLE_ADMIN = User.createUserForTesting(conf, "UserA", new String[0]);
2204 
2205     // Grant TABLE ADMIN privs
2206     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2207       Permission.Action.ADMIN);
2208     try {
2209       AccessTestAction listTablesAction = new AccessTestAction() {
2210         @Override
2211         public Object run() throws Exception {
2212           try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2213               Admin admin = conn.getAdmin()) {
2214             return Arrays.asList(admin.listTables());
2215           }
2216         }
2217       };
2218 
2219       AccessTestAction getTableDescAction = new AccessTestAction() {
2220         @Override
2221         public Object run() throws Exception {
2222           try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2223               Admin admin = conn.getAdmin();) {
2224             return admin.getTableDescriptor(TEST_TABLE);
2225           }
2226         }
2227       };
2228 
2229       verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, TABLE_ADMIN,
2230         USER_GROUP_CREATE, USER_GROUP_ADMIN);
2231       verifyIfEmptyList(listTablesAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2232         USER_GROUP_WRITE);
2233 
2234       verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER,
2235         TABLE_ADMIN, USER_GROUP_CREATE, USER_GROUP_ADMIN);
2236       verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2237         USER_GROUP_WRITE);
2238     } finally {
2239       // Cleanup, revoke TABLE ADMIN privs
2240       revokeFromTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2241         Permission.Action.ADMIN);
2242     }
2243   }
2244 
2245   @Test (timeout=180000)
2246   public void testTableNameEnumeration() throws Exception {
2247     AccessTestAction listTablesAction = new AccessTestAction() {
2248       @Override
2249       public Object run() throws Exception {
2250         Connection unmanagedConnection =
2251             ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2252         Admin admin = unmanagedConnection.getAdmin();
2253         try {
2254           return Arrays.asList(admin.listTableNames());
2255         } finally {
2256           admin.close();
2257           unmanagedConnection.close();
2258         }
2259       }
2260     };
2261 
2262     verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW,
2263       USER_RO, USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_WRITE);
2264     verifyIfEmptyList(listTablesAction, USER_NONE);
2265   }
2266 
2267   @Test (timeout=180000)
2268   public void testTableDeletion() throws Exception {
2269     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
2270     final TableName tname = TableName.valueOf("testTableDeletion");
2271     createTestTable(tname);
2272 
2273     // Grant TABLE ADMIN privs
2274     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), tname, null, null, Permission.Action.ADMIN);
2275 
2276     AccessTestAction deleteTableAction = new AccessTestAction() {
2277       @Override
2278       public Object run() throws Exception {
2279         Connection unmanagedConnection =
2280             ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2281         Admin admin = unmanagedConnection.getAdmin();
2282         try {
2283           deleteTable(TEST_UTIL, admin, tname);
2284         } finally {
2285           admin.close();
2286           unmanagedConnection.close();
2287         }
2288         return null;
2289       }
2290     };
2291 
2292     verifyDenied(deleteTableAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2293       USER_GROUP_WRITE);
2294     verifyAllowed(deleteTableAction, TABLE_ADMIN);
2295   }
2296 
2297   private void createTestTable(TableName tname) throws Exception {
2298     HTableDescriptor htd = new HTableDescriptor(tname);
2299     HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
2300     hcd.setMaxVersions(100);
2301     htd.addFamily(hcd);
2302     htd.setOwner(USER_OWNER);
2303     createTable(TEST_UTIL, htd, new byte[][]{Bytes.toBytes("s")});
2304     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2305   }
2306 
2307   @Test (timeout=180000)
2308   public void testNamespaceUserGrant() throws Exception {
2309     AccessTestAction getAction = new AccessTestAction() {
2310       @Override
2311       public Object run() throws Exception {
2312         try(Connection conn = ConnectionFactory.createConnection(conf);
2313             Table t = conn.getTable(TEST_TABLE);) {
2314           return t.get(new Get(TEST_ROW));
2315         }
2316       }
2317     };
2318 
2319     String namespace = TEST_TABLE.getNamespaceAsString();
2320 
2321     // Grant namespace READ to USER_NONE, this should supersede any table permissions
2322     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2323     // Now USER_NONE should be able to read
2324     verifyAllowed(getAction, USER_NONE);
2325 
2326     // Revoke namespace READ to USER_NONE
2327     revokeFromNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2328     verifyDenied(getAction, USER_NONE);
2329   }
2330 
2331   @Test (timeout=180000)
2332   public void testAccessControlClientGrantRevoke() throws Exception {
2333     // Create user for testing, who has no READ privileges by default.
2334     User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2335     AccessTestAction getAction = new AccessTestAction() {
2336       @Override
2337       public Object run() throws Exception {
2338         try(Connection conn = ConnectionFactory.createConnection(conf);
2339             Table t = conn.getTable(TEST_TABLE);) {
2340           return t.get(new Get(TEST_ROW));
2341         }
2342       }
2343     };
2344 
2345     verifyDenied(getAction, testGrantRevoke);
2346 
2347     // Grant table READ permissions to testGrantRevoke.
2348     try {
2349       grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2350         testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2351     } catch (Throwable e) {
2352       LOG.error("error during call of AccessControlClient.grant. ", e);
2353     }
2354 
2355     // Now testGrantRevoke should be able to read also
2356     verifyAllowed(getAction, testGrantRevoke);
2357 
2358     // Revoke table READ permission to testGrantRevoke.
2359     try {
2360       revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2361         testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2362     } catch (Throwable e) {
2363       LOG.error("error during call of AccessControlClient.revoke ", e);
2364     }
2365 
2366     // Now testGrantRevoke shouldn't be able read
2367     verifyDenied(getAction, testGrantRevoke);
2368   }
2369 
2370   @Test (timeout=180000)
2371   public void testAccessControlClientGlobalGrantRevoke() throws Exception {
2372     // Create user for testing, who has no READ privileges by default.
2373     User testGlobalGrantRevoke = User.createUserForTesting(conf,
2374       "testGlobalGrantRevoke", new String[0]);
2375     AccessTestAction getAction = new AccessTestAction() {
2376       @Override
2377       public Object run() throws Exception {
2378         try(Connection conn = ConnectionFactory.createConnection(conf);
2379             Table t = conn.getTable(TEST_TABLE)) {
2380           return t.get(new Get(TEST_ROW));
2381         }
2382       }
2383     };
2384 
2385     verifyDenied(getAction, testGlobalGrantRevoke);
2386 
2387     // Grant table READ permissions to testGlobalGrantRevoke.
2388     String userName = testGlobalGrantRevoke.getShortName();
2389     try {
2390       grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2391         Permission.Action.READ);
2392     } catch (Throwable e) {
2393       LOG.error("error during call of AccessControlClient.grant. ", e);
2394     }
2395     try {
2396       // Now testGlobalGrantRevoke should be able to read also
2397       verifyAllowed(getAction, testGlobalGrantRevoke);
2398     } catch (Exception e) {
2399       revokeGlobal(TEST_UTIL, userName, Permission.Action.READ);
2400       throw e;
2401     }
2402 
2403     // Revoke table READ permission to testGlobalGrantRevoke.
2404     try {
2405       revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2406         Permission.Action.READ);
2407     } catch (Throwable e) {
2408       LOG.error("error during call of AccessControlClient.revoke ", e);
2409     }
2410 
2411     // Now testGlobalGrantRevoke shouldn't be able read
2412     verifyDenied(getAction, testGlobalGrantRevoke);
2413 
2414   }
2415 
2416   @Test(timeout = 180000)
2417   public void testAccessControlClientGrantRevokeWithMultiActions() throws Exception {
2418     User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2419     AccessTestAction getAction = new AccessTestAction() {
2420       @Override
2421       public Object run() throws Exception {
2422         try (Connection conn = ConnectionFactory.createConnection(conf);
2423             Table t = conn.getTable(TEST_TABLE)) {
2424           return t.get(new Get(TEST_ROW));
2425         }
2426       }
2427     };
2428 
2429     AccessTestAction putAction = new AccessTestAction() {
2430       @Override
2431       public Object run() throws Exception {
2432         Put p = new Put(TEST_ROW);
2433         p.addColumn(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
2434         try (Connection conn = ConnectionFactory.createConnection(conf);
2435             Table t = conn.getTable(TEST_TABLE)) {
2436           t.put(p);
2437           return null;
2438         }
2439       }
2440     };
2441 
2442     verifyDenied(getAction, testGrantRevoke);
2443     verifyDenied(putAction, testGrantRevoke);
2444 
2445     // Grant global READ permissions to testGrantRevoke.
2446     String userName = testGrantRevoke.getShortName();
2447     try {
2448       grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, true,
2449         Permission.Action.READ);
2450     } catch (Throwable e) {
2451       LOG.error("error during call of AccessControlClient.grant. ", e);
2452     }
2453     verifyAllowed(getAction, testGrantRevoke);
2454     verifyDenied(putAction, testGrantRevoke);
2455 
2456     // Grant global READ permissions to testGrantRevoke.
2457     try {
2458       grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, true,
2459         Permission.Action.WRITE);
2460     } catch (Throwable e) {
2461       LOG.error("error during call of AccessControlClient.grant. ", e);
2462     }
2463     verifyAllowed(getAction, testGrantRevoke);
2464     verifyAllowed(putAction, testGrantRevoke);
2465 
2466     // Revoke global READ permission to testGrantRevoke.
2467     try {
2468       revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2469         Permission.Action.READ, Permission.Action.WRITE);
2470     } catch (Throwable e) {
2471       LOG.error("error during call of AccessControlClient.revoke ", e);
2472     }
2473     verifyDenied(getAction, testGrantRevoke);
2474     verifyDenied(putAction, testGrantRevoke);
2475 
2476     // Grant table READ & WRITE permissions to testGrantRevoke
2477     try {
2478       grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2479         null, null, true, Permission.Action.READ);
2480     } catch (Throwable e) {
2481       LOG.error("error during call of AccessControlClient.grant. ", e);
2482     }
2483     verifyAllowed(getAction, testGrantRevoke);
2484     verifyDenied(putAction, testGrantRevoke);
2485 
2486     // Grant table WRITE permissions to testGrantRevoke
2487     try {
2488       grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2489         null, null, true, Action.WRITE);
2490     } catch (Throwable e) {
2491       LOG.error("error during call of AccessControlClient.grant. ", e);
2492     }
2493     verifyAllowed(getAction, testGrantRevoke);
2494     verifyAllowed(putAction, testGrantRevoke);
2495 
2496     // Revoke table READ & WRITE permission to testGrantRevoke.
2497     try {
2498       revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2499         null, null, Permission.Action.READ, Permission.Action.WRITE);
2500     } catch (Throwable e) {
2501       LOG.error("error during call of AccessControlClient.revoke ", e);
2502     }
2503     verifyDenied(getAction, testGrantRevoke);
2504     verifyDenied(putAction, testGrantRevoke);
2505 
2506     // Grant Namespace READ permissions to testGrantRevoke
2507     String namespace = TEST_TABLE.getNamespaceAsString();
2508     try {
2509       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2510         namespace, true, Permission.Action.READ);
2511     } catch (Throwable e) {
2512       LOG.error("error during call of AccessControlClient.grant. ", e);
2513     }
2514     verifyAllowed(getAction, testGrantRevoke);
2515     verifyDenied(putAction, testGrantRevoke);
2516 
2517     // Grant Namespace WRITE permissions to testGrantRevoke
2518     try {
2519       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2520         namespace, true, Permission.Action.WRITE);
2521     } catch (Throwable e) {
2522       LOG.error("error during call of AccessControlClient.grant. ", e);
2523     }
2524     verifyAllowed(getAction, testGrantRevoke);
2525     verifyAllowed(putAction, testGrantRevoke);
2526 
2527     // Revoke table READ & WRITE permission to testGrantRevoke.
2528     try {
2529       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2530         TEST_TABLE.getNamespaceAsString(), Permission.Action.READ, Permission.Action.WRITE);
2531     } catch (Throwable e) {
2532       LOG.error("error during call of AccessControlClient.revoke ", e);
2533     }
2534     verifyDenied(getAction, testGrantRevoke);
2535     verifyDenied(putAction, testGrantRevoke);
2536   }
2537 
2538   @Test (timeout=180000)
2539   public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
2540     // Create user for testing, who has no READ privileges by default.
2541     User testNS = User.createUserForTesting(conf, "testNS", new String[0]);
2542     AccessTestAction getAction = new AccessTestAction() {
2543       @Override
2544       public Object run() throws Exception {
2545         try(Connection conn = ConnectionFactory.createConnection(conf);
2546             Table t = conn.getTable(TEST_TABLE);) {
2547           return t.get(new Get(TEST_ROW));
2548         }
2549       }
2550     };
2551 
2552     verifyDenied(getAction, testNS);
2553 
2554     String userName = testNS.getShortName();
2555     String namespace = TEST_TABLE.getNamespaceAsString();
2556     // Grant namespace READ to testNS, this should supersede any table permissions
2557     try {
2558       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, namespace,
2559         Permission.Action.READ);
2560     } catch (Throwable e) {
2561       LOG.error("error during call of AccessControlClient.grant. ", e);
2562     }
2563     try {
2564       // Now testNS should be able to read also
2565       verifyAllowed(getAction, testNS);
2566     } catch (Exception e) {
2567       revokeFromNamespace(TEST_UTIL, userName, namespace, Permission.Action.READ);
2568       throw e;
2569     }
2570 
2571     // Revoke namespace READ to testNS, this should supersede any table permissions
2572     try {
2573       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2574         namespace, Permission.Action.READ);
2575     } catch (Throwable e) {
2576       LOG.error("error during call of AccessControlClient.revoke ", e);
2577     }
2578 
2579     // Now testNS shouldn't be able read
2580     verifyDenied(getAction, testNS);
2581   }
2582 
2583 
2584   public static class PingCoprocessor extends PingService implements Coprocessor,
2585       CoprocessorService {
2586 
2587     @Override
2588     public void start(CoprocessorEnvironment env) throws IOException { }
2589 
2590     @Override
2591     public void stop(CoprocessorEnvironment env) throws IOException { }
2592 
2593     @Override
2594     public Service getService() {
2595       return this;
2596     }
2597 
2598     @Override
2599     public void ping(RpcController controller, PingRequest request,
2600         RpcCallback<PingResponse> callback) {
2601       callback.run(PingResponse.newBuilder().setPong("Pong!").build());
2602     }
2603 
2604     @Override
2605     public void count(RpcController controller, CountRequest request,
2606         RpcCallback<CountResponse> callback) {
2607       callback.run(CountResponse.newBuilder().build());
2608     }
2609 
2610     @Override
2611     public void increment(RpcController controller, IncrementCountRequest requet,
2612         RpcCallback<IncrementCountResponse> callback) {
2613       callback.run(IncrementCountResponse.newBuilder().build());
2614     }
2615 
2616     @Override
2617     public void hello(RpcController controller, HelloRequest request,
2618         RpcCallback<HelloResponse> callback) {
2619       callback.run(HelloResponse.newBuilder().setResponse("Hello!").build());
2620     }
2621 
2622     @Override
2623     public void noop(RpcController controller, NoopRequest request,
2624         RpcCallback<NoopResponse> callback) {
2625       callback.run(NoopResponse.newBuilder().build());
2626     }
2627   }
2628 
2629   @Test (timeout=180000)
2630   public void testCoprocessorExec() throws Exception {
2631     // Set up our ping endpoint service on all regions of our test table
2632     for (JVMClusterUtil.RegionServerThread thread:
2633         TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
2634       HRegionServer rs = thread.getRegionServer();
2635       for (Region region: rs.getOnlineRegions(TEST_TABLE)) {
2636         region.getCoprocessorHost().load(PingCoprocessor.class,
2637           Coprocessor.PRIORITY_USER, conf);
2638       }
2639     }
2640 
2641     // Create users for testing, and grant EXEC privileges on our test table
2642     // only to user A
2643     User userA = User.createUserForTesting(conf, "UserA", new String[0]);
2644     User userB = User.createUserForTesting(conf, "UserB", new String[0]);
2645 
2646     grantOnTable(TEST_UTIL, userA.getShortName(),
2647       TEST_TABLE, null, null,
2648       Permission.Action.EXEC);
2649     try {
2650       // Create an action for invoking our test endpoint
2651       AccessTestAction execEndpointAction = new AccessTestAction() {
2652         @Override
2653         public Object run() throws Exception {
2654           try (Connection conn = ConnectionFactory.createConnection(conf);
2655               Table t = conn.getTable(TEST_TABLE);) {
2656             BlockingRpcChannel service = t.coprocessorService(HConstants.EMPTY_BYTE_ARRAY);
2657             PingCoprocessor.newBlockingStub(service).noop(null, NoopRequest.newBuilder().build());
2658           }
2659           return null;
2660         }
2661       };
2662 
2663       String namespace = TEST_TABLE.getNamespaceAsString();
2664       // Now grant EXEC to the entire namespace to user B
2665       grantOnNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2666       // User B should now be allowed also
2667       verifyAllowed(execEndpointAction, userA, userB);
2668 
2669       revokeFromNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2670       // Verify that EXEC permission is checked correctly
2671       verifyDenied(execEndpointAction, userB);
2672       verifyAllowed(execEndpointAction, userA);
2673     } finally {
2674       // Cleanup, revoke the userA privileges
2675       revokeFromTable(TEST_UTIL, userA.getShortName(), TEST_TABLE, null, null,
2676         Permission.Action.EXEC);
2677     }
2678   }
2679 
2680   @Test (timeout=180000)
2681   public void testSetQuota() throws Exception {
2682     AccessTestAction setUserQuotaAction = new AccessTestAction() {
2683       @Override
2684       public Object run() throws Exception {
2685         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2686           null, null);
2687         return null;
2688       }
2689     };
2690 
2691     AccessTestAction setUserTableQuotaAction = new AccessTestAction() {
2692       @Override
2693       public Object run() throws Exception {
2694         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null), null,
2695           TEST_TABLE, null);
2696         return null;
2697       }
2698     };
2699 
2700     AccessTestAction setUserNamespaceQuotaAction = new AccessTestAction() {
2701       @Override
2702       public Object run() throws Exception {
2703         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2704           null, (String)null, null);
2705         return null;
2706       }
2707     };
2708 
2709     AccessTestAction setTableQuotaAction = new AccessTestAction() {
2710       @Override
2711       public Object run() throws Exception {
2712         ACCESS_CONTROLLER.preSetTableQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2713           TEST_TABLE, null);
2714         return null;
2715       }
2716     };
2717 
2718     AccessTestAction setNamespaceQuotaAction = new AccessTestAction() {
2719       @Override
2720       public Object run() throws Exception {
2721         ACCESS_CONTROLLER.preSetNamespaceQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2722           null, null);
2723         return null;
2724       }
2725     };
2726 
2727     verifyAllowed(setUserQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2728     verifyDenied(setUserQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2729       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2730 
2731     verifyAllowed(setUserTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2732     verifyDenied(setUserTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE,
2733       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2734 
2735     verifyAllowed(setUserNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2736     verifyDenied(setUserNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2737       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2738 
2739     verifyAllowed(setTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2740     verifyDenied(setTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
2741 
2742     verifyAllowed(setNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2743     verifyDenied(setNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2744       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2745   }
2746 
2747   @Test (timeout=180000)
2748   public void testGetNamespacePermission() throws Exception {
2749     String namespace = "testGetNamespacePermission";
2750     NamespaceDescriptor desc = NamespaceDescriptor.create(namespace).build();
2751     createNamespace(TEST_UTIL, desc);
2752     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2753 
2754     // Test 1: A specific namespace
2755     getNamespacePermissionsAndVerify(namespace, 1, namespace);
2756 
2757     // Test 2: '@.*'
2758     getNamespacePermissionsAndVerify(".*", 1, namespace);
2759 
2760     // Test 3: A more complex regex
2761     getNamespacePermissionsAndVerify("^test[a-zA-Z]*", 1, namespace);
2762 
2763     deleteNamespace(TEST_UTIL, namespace);
2764   }
2765 
2766   /**
2767    * List all user permissions match the given regular expression for namespace
2768    * and verify each of them.
2769    * @param namespaceRegexWithoutPrefix the regualar expression for namespace, without NAMESPACE_PREFIX
2770    * @param expectedAmount the expected amount of user permissions returned
2771    * @param expectedNamespace the expected namespace of each user permission returned
2772    * @throws HBaseException in the case of any HBase exception when accessing hbase:acl table
2773    */
2774   private void getNamespacePermissionsAndVerify(String namespaceRegexWithoutPrefix,
2775       int expectedAmount, String expectedNamespace) throws HBaseException {
2776     try {
2777       List<UserPermission> namespacePermissions = AccessControlClient.getUserPermissions(
2778         systemUserConnection, AccessControlLists.toNamespaceEntry(namespaceRegexWithoutPrefix));
2779       assertTrue(namespacePermissions != null);
2780       assertEquals(expectedAmount, namespacePermissions.size());
2781       for (UserPermission namespacePermission : namespacePermissions) {
2782         assertFalse(namespacePermission.isGlobal());  // Verify it is not a global user permission
2783         assertEquals(expectedNamespace, namespacePermission.getNamespace());  // Verify namespace is set
2784       }
2785     } catch (Throwable thw) {
2786       throw new HBaseException(thw);
2787     }
2788   }
2789 
2790   @Test (timeout=180000)
2791   public void testTruncatePerms() throws Exception {
2792     try {
2793       List<UserPermission> existingPerms = AccessControlClient.getUserPermissions(
2794           systemUserConnection, TEST_TABLE.getNameAsString());
2795       assertTrue(existingPerms != null);
2796       assertTrue(existingPerms.size() > 1);
2797       TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE);
2798       TEST_UTIL.truncateTable(TEST_TABLE);
2799       TEST_UTIL.waitTableAvailable(TEST_TABLE);
2800       List<UserPermission> perms = AccessControlClient.getUserPermissions(
2801           systemUserConnection, TEST_TABLE.getNameAsString());
2802       assertTrue(perms != null);
2803       assertEquals(existingPerms.size(), perms.size());
2804     } catch (Throwable e) {
2805       throw new HBaseIOException(e);
2806     }
2807   }
2808 
2809   private PrivilegedAction<List<UserPermission>> getPrivilegedAction(final String regex) {
2810     return new PrivilegedAction<List<UserPermission>>() {
2811       @Override
2812       public List<UserPermission> run() {
2813         try(Connection conn = ConnectionFactory.createConnection(conf);) {
2814           return AccessControlClient.getUserPermissions(conn, regex);
2815         } catch (Throwable e) {
2816           LOG.error("error during call of AccessControlClient.getUserPermissions.", e);
2817           return null;
2818         }
2819       }
2820     };
2821   }
2822 
2823   @Test (timeout=180000)
2824   public void testAccessControlClientUserPerms() throws Exception {
2825     TableName tname = TableName.valueOf("testAccessControlClientUserPerms");
2826     createTestTable(tname);
2827     try {
2828       final String regex = tname.getNameWithNamespaceInclAsString();
2829       User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new String[0]);
2830       assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
2831       // Grant TABLE ADMIN privs to testUserPerms
2832       grantOnTable(TEST_UTIL, testUserPerms.getShortName(), tname, null, null, Action.ADMIN);
2833       List<UserPermission> perms = testUserPerms.runAs(getPrivilegedAction(regex));
2834       assertNotNull(perms);
2835       // Superuser, testUserPerms
2836       assertEquals(2, perms.size());
2837     } finally {
2838       deleteTable(TEST_UTIL, tname);
2839     }
2840   }
2841 
2842   @Test (timeout=180000)
2843   public void testAccessControllerUserPermsRegexHandling() throws Exception {
2844     User testRegexHandler = User.createUserForTesting(conf, "testRegexHandling", new String[0]);
2845 
2846     final String REGEX_ALL_TABLES = ".*";
2847     final String tableName = "testRegex";
2848     final TableName table1 = TableName.valueOf(tableName);
2849     final byte[] family = Bytes.toBytes("f1");
2850 
2851     // create table in default ns
2852     Admin admin = TEST_UTIL.getHBaseAdmin();
2853     HTableDescriptor htd = new HTableDescriptor(table1);
2854     htd.addFamily(new HColumnDescriptor(family));
2855     createTable(TEST_UTIL, htd);
2856     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2857 
2858     // creating the ns and table in it
2859     String ns = "testNamespace";
2860     NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
2861     final TableName table2 = TableName.valueOf(ns, tableName);
2862     createNamespace(TEST_UTIL, desc);
2863     htd = new HTableDescriptor(table2);
2864     htd.addFamily(new HColumnDescriptor(family));
2865     createTable(TEST_UTIL, htd);
2866     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2867 
2868     // Verify that we can read sys-tables
2869     String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString();
2870     assertEquals(5, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
2871     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
2872 
2873     // Grant TABLE ADMIN privs to testUserPerms
2874     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2875     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, null, Action.ADMIN);
2876     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2877     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, null, Action.ADMIN);
2878     assertEquals(4, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2879 
2880     // USER_ADMIN, testUserPerms must have a row each.
2881     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
2882     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
2883           NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + TableName.NAMESPACE_DELIM + tableName)
2884         ).size());
2885     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
2886         ns + TableName.NAMESPACE_DELIM + tableName)).size());
2887     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
2888 
2889     deleteTable(TEST_UTIL, table1);
2890     deleteTable(TEST_UTIL, table2);
2891     deleteNamespace(TEST_UTIL, ns);
2892   }
2893 
2894   private void verifyAnyCreate(AccessTestAction action) throws Exception {
2895     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_ADMIN_CF,
2896       USER_GROUP_CREATE);
2897     verifyDenied(action, USER_NONE, USER_RO, USER_RW, USER_GROUP_READ, USER_GROUP_WRITE,
2898       USER_GROUP_ADMIN);
2899   }
2900 
2901   @Test (timeout=180000)
2902   public void testPrepareAndCleanBulkLoad() throws Exception {
2903     AccessTestAction prepareBulkLoadAction = new AccessTestAction() {
2904       @Override
2905       public Object run() throws Exception {
2906         ACCESS_CONTROLLER.prePrepareBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
2907           null);
2908         return null;
2909       }
2910     };
2911     AccessTestAction cleanupBulkLoadAction = new AccessTestAction() {
2912       @Override
2913       public Object run() throws Exception {
2914         ACCESS_CONTROLLER.preCleanupBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
2915           null);
2916         return null;
2917       }
2918     };
2919     verifyAnyCreate(prepareBulkLoadAction);
2920     verifyAnyCreate(cleanupBulkLoadAction);
2921   }
2922 
2923   @Test (timeout=180000)
2924   public void testReplicateLogEntries() throws Exception {
2925     AccessTestAction replicateLogEntriesAction = new AccessTestAction() {
2926       @Override
2927       public Object run() throws Exception {
2928         ACCESS_CONTROLLER.preReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2929           null, null);
2930         ACCESS_CONTROLLER.postReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2931           null, null);
2932         return null;
2933       }
2934     };
2935 
2936     verifyAllowed(replicateLogEntriesAction, SUPERUSER, USER_ADMIN, USER_GROUP_WRITE);
2937     verifyDenied(replicateLogEntriesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2938       USER_GROUP_READ, USER_GROUP_ADMIN, USER_GROUP_CREATE);
2939   }
2940 
2941   @Test
2942   public void testAccessControlRevokeOnlyFewPermission() throws Throwable {
2943     TableName tname = TableName.valueOf("revoke");
2944     try {
2945       TEST_UTIL.createTable(tname, TEST_FAMILY);
2946       TEST_UTIL.waitUntilAllRegionsAssigned(tname);
2947 
2948       User testUserPerms = User.createUserForTesting(conf, "revokePerms", new String[0]);
2949       Permission.Action[] actions = { Action.READ, Action.WRITE };
2950       AccessControlClient.grant(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
2951         null, null, actions);
2952 
2953       List<UserPermission> userPermissions = AccessControlClient
2954           .getUserPermissions(TEST_UTIL.getConnection(), tname.getNameAsString());
2955       assertEquals(2, userPermissions.size());
2956 
2957       AccessControlClient.revoke(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
2958         null, null, Action.WRITE);
2959 
2960       userPermissions = AccessControlClient.getUserPermissions(TEST_UTIL.getConnection(),
2961         tname.getNameAsString());
2962       assertEquals(2, userPermissions.size());
2963 
2964       Permission.Action[] expectedAction = { Action.READ };
2965       boolean userFound = false;
2966       for (UserPermission p : userPermissions) {
2967         if (testUserPerms.getShortName().equals(Bytes.toString(p.getUser()))) {
2968           assertArrayEquals(expectedAction, p.getActions());
2969           userFound = true;
2970           break;
2971         }
2972       }
2973       assertTrue(userFound);
2974     } finally {
2975       TEST_UTIL.deleteTable(tname);
2976     }
2977   }
2978 
2979   @Test
2980   public void testGetClusterStatus() throws Exception {
2981     AccessTestAction action = new AccessTestAction() {
2982       @Override
2983       public Object run() throws Exception {
2984       ACCESS_CONTROLLER.preGetClusterStatus(ObserverContext.createAndPrepare(CP_ENV, null));
2985       return null;
2986       }
2987     };
2988 
2989     verifyAllowed(
2990         action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
2991   }
2992 }