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.security.Superusers;
56  import org.apache.hadoop.hbase.testclassification.LargeTests;
57  import org.apache.hadoop.hbase.MiniHBaseCluster;
58  import org.apache.hadoop.hbase.NamespaceDescriptor;
59  import org.apache.hadoop.hbase.ServerName;
60  import org.apache.hadoop.hbase.TableName;
61  import org.apache.hadoop.hbase.TableNotFoundException;
62  import org.apache.hadoop.hbase.Tag;
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.HBaseProtos.SnapshotDescription;
114 import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState;
115 import org.apache.hadoop.hbase.regionserver.HRegion;
116 import org.apache.hadoop.hbase.regionserver.HRegionServer;
117 import org.apache.hadoop.hbase.regionserver.Region;
118 import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
119 import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
120 import org.apache.hadoop.hbase.regionserver.ScanType;
121 import org.apache.hadoop.hbase.security.User;
122 import org.apache.hadoop.hbase.security.access.Permission.Action;
123 import org.apache.hadoop.hbase.util.Bytes;
124 import org.apache.hadoop.hbase.util.JVMClusterUtil;
125 import org.apache.log4j.Level;
126 import org.apache.log4j.Logger;
127 import org.junit.AfterClass;
128 import org.junit.BeforeClass;
129 import org.junit.Test;
130 import org.junit.experimental.categories.Category;
131 
132 import com.google.protobuf.BlockingRpcChannel;
133 import com.google.protobuf.RpcCallback;
134 import com.google.protobuf.RpcController;
135 import com.google.protobuf.Service;
136 import com.google.protobuf.ServiceException;
137 
138 /**
139  * Performs authorization checks for common operations, according to different
140  * levels of authorized users.
141  */
142 @Category(LargeTests.class)
143 public class TestAccessController extends SecureTestUtil {
144   private static final Log LOG = LogFactory.getLog(TestAccessController.class);
145 
146   static {
147     Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
148     Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
149     Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
150   }
151 
152   private static TableName TEST_TABLE = TableName.valueOf("testtable1");
153   private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
154   private static Configuration conf;
155 
156   /** The systemUserConnection created here is tied to the system user. In case, you are planning
157    * to create AccessTestAction, DON'T use this systemUserConnection as the 'doAs' user
158    * gets  eclipsed by the system user. */
159   private static Connection systemUserConnection;
160 
161 
162   // user with all permissions
163   private static User SUPERUSER;
164   // user granted with all global permission
165   private static User USER_ADMIN;
166   // user with rw permissions on column family.
167   private static User USER_RW;
168   // user with read-only permissions
169   private static User USER_RO;
170   // user is table owner. will have all permissions on table
171   private static User USER_OWNER;
172   // user with create table permissions alone
173   private static User USER_CREATE;
174   // user with no permissions
175   private static User USER_NONE;
176   // user with admin rights on the column family
177   private static User USER_ADMIN_CF;
178 
179   private static final String GROUP_ADMIN = "group_admin";
180   private static final String GROUP_CREATE = "group_create";
181   private static final String GROUP_READ = "group_read";
182   private static final String GROUP_WRITE = "group_write";
183 
184   private static User USER_GROUP_ADMIN;
185   private static User USER_GROUP_CREATE;
186   private static User USER_GROUP_READ;
187   private static User USER_GROUP_WRITE;
188 
189   // TODO: convert this test to cover the full matrix in
190   // https://hbase.apache.org/book/appendix_acl_matrix.html
191   // creating all Scope x Permission combinations
192 
193   private static TableName TEST_TABLE2 = TableName.valueOf("testtable2");
194   private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
195   private static byte[] TEST_QUALIFIER = Bytes.toBytes("q1");
196   private static byte[] TEST_ROW = Bytes.toBytes("r1");
197 
198   private static MasterCoprocessorEnvironment CP_ENV;
199   private static AccessController ACCESS_CONTROLLER;
200   private static RegionServerCoprocessorEnvironment RSCP_ENV;
201   private static RegionCoprocessorEnvironment RCP_ENV;
202 
203   @BeforeClass
204   public static void setupBeforeClass() throws Exception {
205     // setup configuration
206     conf = TEST_UTIL.getConfiguration();
207     // Up the handlers; this test needs more than usual.
208     conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
209     // Enable security
210     enableSecurity(conf);
211     // In this particular test case, we can't use SecureBulkLoadEndpoint because its doAs will fail
212     // to move a file for a random user
213     conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
214     // Verify enableSecurity sets up what we require
215     verifyConfiguration(conf);
216 
217     // Enable EXEC permission checking
218     conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true);
219 
220     TEST_UTIL.startMiniCluster();
221     MasterCoprocessorHost cpHost =
222       TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
223     cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
224     ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(AccessController.class.getName());
225     CP_ENV = cpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
226       Coprocessor.PRIORITY_HIGHEST, 1, conf);
227     RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
228       .getRegionServerCoprocessorHost();
229     RSCP_ENV = rsHost.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           } catch (IOException e) {
953           } finally {
954             scanner.close();
955           }
956         }
957         return null;
958       }
959     };
960     verifyRead(scanAction);
961   }
962 
963   @Test (timeout=180000)
964   // test put, delete, increment
965   public void testWrite() throws Exception {
966     // put action
967     AccessTestAction putAction = new AccessTestAction() {
968       @Override
969       public Object run() throws Exception {
970         Put p = new Put(TEST_ROW);
971         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
972         try(Connection conn = ConnectionFactory.createConnection(conf);
973             Table t = conn.getTable(TEST_TABLE)) {
974           t.put(p);
975         }
976         return null;
977       }
978     };
979     verifyWrite(putAction);
980 
981     // delete action
982     AccessTestAction deleteAction = new AccessTestAction() {
983       @Override
984       public Object run() throws Exception {
985         Delete d = new Delete(TEST_ROW);
986         d.deleteFamily(TEST_FAMILY);
987         try(Connection conn = ConnectionFactory.createConnection(conf);
988             Table t = conn.getTable(TEST_TABLE)) {
989           t.delete(d);
990         }
991         return null;
992       }
993     };
994     verifyWrite(deleteAction);
995 
996     // increment action
997     AccessTestAction incrementAction = new AccessTestAction() {
998       @Override
999       public Object run() throws Exception {
1000         Increment inc = new Increment(TEST_ROW);
1001         inc.addColumn(TEST_FAMILY, TEST_QUALIFIER, 1);
1002         try(Connection conn = ConnectionFactory.createConnection(conf);
1003             Table t = conn.getTable(TEST_TABLE);) {
1004           t.increment(inc);
1005         }
1006         return null;
1007       }
1008     };
1009     verifyWrite(incrementAction);
1010   }
1011 
1012   @Test (timeout=180000)
1013   public void testReadWrite() throws Exception {
1014     // action for checkAndDelete
1015     AccessTestAction checkAndDeleteAction = new AccessTestAction() {
1016       @Override
1017       public Object run() throws Exception {
1018         Delete d = new Delete(TEST_ROW);
1019         d.deleteFamily(TEST_FAMILY);
1020         try(Connection conn = ConnectionFactory.createConnection(conf);
1021             Table t = conn.getTable(TEST_TABLE);) {
1022           t.checkAndDelete(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
1023               Bytes.toBytes("test_value"), d);
1024         }
1025         return null;
1026       }
1027     };
1028     verifyReadWrite(checkAndDeleteAction);
1029 
1030     // action for checkAndPut()
1031     AccessTestAction checkAndPut = new AccessTestAction() {
1032       @Override
1033       public Object run() throws Exception {
1034         Put p = new Put(TEST_ROW);
1035         p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
1036         try(Connection conn = ConnectionFactory.createConnection(conf);
1037             Table t = conn.getTable(TEST_TABLE);) {
1038           t.checkAndPut(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
1039               Bytes.toBytes("test_value"), p);
1040         }
1041         return null;
1042       }
1043     };
1044     verifyReadWrite(checkAndPut);
1045   }
1046 
1047   @Test (timeout=180000)
1048   public void testBulkLoad() throws Exception {
1049     try {
1050       FileSystem fs = TEST_UTIL.getTestFileSystem();
1051       final Path dir = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoad");
1052       fs.mkdirs(dir);
1053       // need to make it globally writable
1054       // so users creating HFiles have write permissions
1055       fs.setPermission(dir, FsPermission.valueOf("-rwxrwxrwx"));
1056 
1057       AccessTestAction bulkLoadAction = new AccessTestAction() {
1058         @Override
1059         public Object run() throws Exception {
1060           int numRows = 3;
1061 
1062           // Making the assumption that the test table won't split between the range
1063           byte[][][] hfileRanges = { { { (byte) 0 }, { (byte) 9 } } };
1064 
1065           Path bulkLoadBasePath = new Path(dir, new Path(User.getCurrent().getName()));
1066           new BulkLoadHelper(bulkLoadBasePath).bulkLoadHFile(TEST_TABLE, TEST_FAMILY,
1067             TEST_QUALIFIER, hfileRanges, numRows);
1068 
1069           return null;
1070         }
1071       };
1072 
1073       // User performing bulk loads must have privilege to read table metadata
1074       // (ADMIN or CREATE)
1075       verifyAllowed(bulkLoadAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
1076         USER_GROUP_CREATE);
1077       verifyDenied(bulkLoadAction, USER_RW, USER_NONE, USER_RO, USER_GROUP_READ, USER_GROUP_WRITE,
1078         USER_GROUP_ADMIN);
1079     } finally {
1080       // Reinit after the bulk upload
1081       TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE);
1082       TEST_UTIL.getHBaseAdmin().enableTable(TEST_TABLE);
1083     }
1084   }
1085 
1086   public class BulkLoadHelper {
1087     private final FileSystem fs;
1088     private final Path loadPath;
1089     private final Configuration conf;
1090 
1091     public BulkLoadHelper(Path loadPath) throws IOException {
1092       fs = TEST_UTIL.getTestFileSystem();
1093       conf = TEST_UTIL.getConfiguration();
1094       loadPath = loadPath.makeQualified(fs);
1095       this.loadPath = loadPath;
1096     }
1097 
1098     private void createHFile(Path path,
1099         byte[] family, byte[] qualifier,
1100         byte[] startKey, byte[] endKey, int numRows) throws IOException {
1101 
1102       HFile.Writer writer = null;
1103       long now = System.currentTimeMillis();
1104       try {
1105         HFileContext context = new HFileContextBuilder().build();
1106         writer = HFile.getWriterFactory(conf, new CacheConfig(conf))
1107             .withPath(fs, path)
1108             .withFileContext(context)
1109             .create();
1110         // subtract 2 since numRows doesn't include boundary keys
1111         for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, true, numRows-2)) {
1112           KeyValue kv = new KeyValue(key, family, qualifier, now, key);
1113           writer.append(kv);
1114         }
1115       } finally {
1116         if(writer != null)
1117           writer.close();
1118       }
1119     }
1120 
1121     private void bulkLoadHFile(
1122         TableName tableName,
1123         byte[] family,
1124         byte[] qualifier,
1125         byte[][][] hfileRanges,
1126         int numRowsPerRange) throws Exception {
1127 
1128       Path familyDir = new Path(loadPath, Bytes.toString(family));
1129       fs.mkdirs(familyDir);
1130       int hfileIdx = 0;
1131       for (byte[][] range : hfileRanges) {
1132         byte[] from = range[0];
1133         byte[] to = range[1];
1134         createHFile(new Path(familyDir, "hfile_"+(hfileIdx++)),
1135             family, qualifier, from, to, numRowsPerRange);
1136       }
1137       //set global read so RegionServer can move it
1138       setPermission(loadPath, FsPermission.valueOf("-rwxrwxrwx"));
1139 
1140       try (Connection conn = ConnectionFactory.createConnection(conf);
1141            HTable table = (HTable)conn.getTable(tableName)) {
1142         TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1143         LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
1144         loader.doBulkLoad(loadPath, table);
1145       }
1146     }
1147 
1148     public void setPermission(Path dir, FsPermission perm) throws IOException {
1149       if(!fs.getFileStatus(dir).isDirectory()) {
1150         fs.setPermission(dir,perm);
1151       }
1152       else {
1153         for(FileStatus el : fs.listStatus(dir)) {
1154           fs.setPermission(el.getPath(), perm);
1155           setPermission(el.getPath() , perm);
1156         }
1157       }
1158     }
1159   }
1160 
1161   @Test (timeout=180000)
1162   public void testAppend() throws Exception {
1163 
1164     AccessTestAction appendAction = new AccessTestAction() {
1165       @Override
1166       public Object run() throws Exception {
1167         byte[] row = TEST_ROW;
1168         byte[] qualifier = TEST_QUALIFIER;
1169         Put put = new Put(row);
1170         put.add(TEST_FAMILY, qualifier, Bytes.toBytes(1));
1171         Append append = new Append(row);
1172         append.add(TEST_FAMILY, qualifier, Bytes.toBytes(2));
1173         try(Connection conn = ConnectionFactory.createConnection(conf);
1174             Table t = conn.getTable(TEST_TABLE)) {
1175           t.put(put);
1176           t.append(append);
1177         }
1178         return null;
1179       }
1180     };
1181 
1182     verifyAllowed(appendAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
1183       USER_GROUP_WRITE);
1184     verifyDenied(appendAction, USER_RO, USER_NONE, USER_GROUP_CREATE, USER_GROUP_READ,
1185       USER_GROUP_ADMIN);
1186   }
1187 
1188   @Test (timeout=180000)
1189   public void testGrantRevoke() throws Exception {
1190     AccessTestAction grantAction = new AccessTestAction() {
1191       @Override
1192       public Object run() throws Exception {
1193         try(Connection conn = ConnectionFactory.createConnection(conf);
1194             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1195           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1196           AccessControlService.BlockingInterface protocol =
1197             AccessControlService.newBlockingStub(service);
1198           ProtobufUtil.grant(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1199             Action.READ);
1200         }
1201         return null;
1202       }
1203     };
1204 
1205     AccessTestAction revokeAction = new AccessTestAction() {
1206       @Override
1207       public Object run() throws Exception {
1208         try(Connection conn = ConnectionFactory.createConnection(conf);
1209             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1210           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1211           AccessControlService.BlockingInterface protocol =
1212             AccessControlService.newBlockingStub(service);
1213           ProtobufUtil.revoke(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1214             Action.READ);
1215         }
1216         return null;
1217       }
1218     };
1219 
1220     AccessTestAction getTablePermissionsAction = new AccessTestAction() {
1221       @Override
1222       public Object run() throws Exception {
1223         try(Connection conn = ConnectionFactory.createConnection(conf);
1224             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)){
1225           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1226           AccessControlService.BlockingInterface protocol =
1227               AccessControlService.newBlockingStub(service);
1228           ProtobufUtil.getUserPermissions(null, protocol, TEST_TABLE);
1229         }
1230         return null;
1231       }
1232     };
1233 
1234     AccessTestAction getGlobalPermissionsAction = new AccessTestAction() {
1235       @Override
1236       public Object run() throws Exception {
1237         try(Connection conn = ConnectionFactory.createConnection(conf);
1238             Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
1239           BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1240           AccessControlService.BlockingInterface protocol =
1241             AccessControlService.newBlockingStub(service);
1242           ProtobufUtil.getUserPermissions(null, protocol);
1243         }
1244         return null;
1245       }
1246     };
1247 
1248     verifyAllowed(grantAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1249     verifyDenied(grantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1250         USER_GROUP_WRITE, USER_GROUP_CREATE);
1251     try {
1252       verifyAllowed(revokeAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1253       verifyDenied(revokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1254         USER_GROUP_WRITE, USER_GROUP_CREATE);
1255 
1256       verifyAllowed(getTablePermissionsAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1257       verifyDenied(getTablePermissionsAction, USER_CREATE, USER_RW, USER_RO, USER_NONE,
1258         USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1259 
1260       verifyAllowed(getGlobalPermissionsAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1261       verifyDenied(getGlobalPermissionsAction, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
1262         USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1263     } finally {
1264       // Cleanup, Grant the revoked permission back to the user
1265       grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1266           Permission.Action.READ);
1267     }
1268   }
1269 
1270   @Test (timeout=180000)
1271   public void testPostGrantRevoke() throws Exception {
1272     final TableName tableName =
1273         TableName.valueOf("TempTable");
1274     final byte[] family1 = Bytes.toBytes("f1");
1275     final byte[] family2 = Bytes.toBytes("f2");
1276     final byte[] qualifier = Bytes.toBytes("q");
1277 
1278     // create table
1279     Admin admin = TEST_UTIL.getHBaseAdmin();
1280     if (admin.tableExists(tableName)) {
1281       deleteTable(TEST_UTIL, tableName);
1282     }
1283     HTableDescriptor htd = new HTableDescriptor(tableName);
1284     htd.addFamily(new HColumnDescriptor(family1));
1285     htd.addFamily(new HColumnDescriptor(family2));
1286     createTable(TEST_UTIL, htd);
1287     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1288     try {
1289       // create temp users
1290       User tblUser =
1291           User.createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]);
1292       User gblUser =
1293           User.createUserForTesting(TEST_UTIL.getConfiguration(), "gbluser", new String[0]);
1294 
1295       // prepare actions:
1296       AccessTestAction putActionAll = new AccessTestAction() {
1297         @Override
1298         public Object run() throws Exception {
1299           Put p = new Put(Bytes.toBytes("a"));
1300           p.add(family1, qualifier, Bytes.toBytes("v1"));
1301           p.add(family2, qualifier, Bytes.toBytes("v2"));
1302           try (Connection conn = ConnectionFactory.createConnection(conf);
1303               Table t = conn.getTable(tableName);) {
1304             t.put(p);
1305           }
1306           return null;
1307         }
1308       };
1309 
1310       AccessTestAction putAction1 = new AccessTestAction() {
1311         @Override
1312         public Object run() throws Exception {
1313           Put p = new Put(Bytes.toBytes("a"));
1314           p.add(family1, qualifier, Bytes.toBytes("v1"));
1315 
1316           try (Connection conn = ConnectionFactory.createConnection(conf);
1317               Table t = conn.getTable(tableName)) {
1318             t.put(p);
1319           }
1320           return null;
1321         }
1322       };
1323 
1324       AccessTestAction putAction2 = new AccessTestAction() {
1325         @Override
1326         public Object run() throws Exception {
1327           Put p = new Put(Bytes.toBytes("a"));
1328           p.add(family2, qualifier, Bytes.toBytes("v2"));
1329           try (Connection conn = ConnectionFactory.createConnection(conf);
1330               Table t = conn.getTable(tableName);) {
1331             t.put(p);
1332           }
1333           return null;
1334         }
1335       };
1336 
1337       AccessTestAction getActionAll = new AccessTestAction() {
1338         @Override
1339         public Object run() throws Exception {
1340           Get g = new Get(TEST_ROW);
1341           g.addFamily(family1);
1342           g.addFamily(family2);
1343           try (Connection conn = ConnectionFactory.createConnection(conf);
1344               Table t = conn.getTable(tableName);) {
1345             t.get(g);
1346           }
1347           return null;
1348         }
1349       };
1350 
1351       AccessTestAction getAction1 = new AccessTestAction() {
1352         @Override
1353         public Object run() throws Exception {
1354           Get g = new Get(TEST_ROW);
1355           g.addFamily(family1);
1356           try (Connection conn = ConnectionFactory.createConnection(conf);
1357               Table t = conn.getTable(tableName)) {
1358             t.get(g);
1359           }
1360           return null;
1361         }
1362       };
1363 
1364       AccessTestAction getAction2 = new AccessTestAction() {
1365         @Override
1366         public Object run() throws Exception {
1367           Get g = new Get(TEST_ROW);
1368           g.addFamily(family2);
1369           try (Connection conn = ConnectionFactory.createConnection(conf);
1370               Table t = conn.getTable(tableName)) {
1371             t.get(g);
1372           }
1373           return null;
1374         }
1375       };
1376 
1377       AccessTestAction deleteActionAll = new AccessTestAction() {
1378         @Override
1379         public Object run() throws Exception {
1380           Delete d = new Delete(TEST_ROW);
1381           d.deleteFamily(family1);
1382           d.deleteFamily(family2);
1383           try (Connection conn = ConnectionFactory.createConnection(conf);
1384               Table t = conn.getTable(tableName)) {
1385             t.delete(d);
1386           }
1387           return null;
1388         }
1389       };
1390 
1391       AccessTestAction deleteAction1 = new AccessTestAction() {
1392         @Override
1393         public Object run() throws Exception {
1394           Delete d = new Delete(TEST_ROW);
1395           d.deleteFamily(family1);
1396           try (Connection conn = ConnectionFactory.createConnection(conf);
1397               Table t = conn.getTable(tableName)) {
1398             t.delete(d);
1399           }
1400           return null;
1401         }
1402       };
1403 
1404       AccessTestAction deleteAction2 = new AccessTestAction() {
1405         @Override
1406         public Object run() throws Exception {
1407           Delete d = new Delete(TEST_ROW);
1408           d.deleteFamily(family2);
1409           try (Connection conn = ConnectionFactory.createConnection(conf);
1410               Table t = conn.getTable(tableName)) {
1411             t.delete(d);
1412           }
1413           return null;
1414         }
1415       };
1416 
1417       // initial check:
1418       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1419       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1420       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1421 
1422       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1423       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1424       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1425 
1426       // grant table read permission
1427       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1428       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null, Permission.Action.READ);
1429 
1430       // check
1431       verifyAllowed(tblUser, getActionAll, getAction1, getAction2);
1432       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1433       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1434 
1435       verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1436       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1437       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1438 
1439       // grant table write permission while revoking read permissions
1440       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1441       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null,
1442         Permission.Action.WRITE);
1443 
1444       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1445       verifyAllowed(tblUser, putActionAll, putAction1, putAction2);
1446       verifyAllowed(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1447 
1448       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1449       verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1450       verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1451 
1452       // revoke table permissions
1453       revokeGlobal(TEST_UTIL, gblUser.getShortName());
1454       revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null);
1455 
1456       verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1457       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1458       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1459 
1460       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1461       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1462       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1463 
1464       // grant column family read permission
1465       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1466       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family1, null,
1467         Permission.Action.READ);
1468 
1469       // Access should be denied for family2
1470       verifyAllowed(tblUser, getActionAll, getAction1);
1471       verifyDenied(tblUser, getAction2);
1472       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1473       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1474 
1475       verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1476       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1477       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1478 
1479       // grant column family write permission
1480       grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1481       grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null,
1482         Permission.Action.WRITE);
1483 
1484       // READ from family1, WRITE to family2 are allowed
1485       verifyAllowed(tblUser, getActionAll, getAction1);
1486       verifyAllowed(tblUser, putAction2, deleteAction2);
1487       verifyDenied(tblUser, getAction2);
1488       verifyDenied(tblUser, putActionAll, putAction1);
1489       verifyDenied(tblUser, deleteActionAll, deleteAction1);
1490 
1491       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1492       verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1493       verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1494 
1495       // revoke column family permission
1496       revokeGlobal(TEST_UTIL, gblUser.getShortName());
1497       revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null);
1498 
1499       // Revoke on family2 should not have impact on family1 permissions
1500       verifyAllowed(tblUser, getActionAll, getAction1);
1501       verifyDenied(tblUser, getAction2);
1502       verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1503       verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1504 
1505       // Should not have access as global permissions are completely revoked
1506       verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1507       verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1508       verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1509     } finally {
1510       // delete table
1511       deleteTable(TEST_UTIL, tableName);
1512     }
1513   }
1514 
1515   private boolean hasFoundUserPermission(List<UserPermission> userPermissions,
1516                                          List<UserPermission> perms) {
1517     return perms.containsAll(userPermissions);
1518   }
1519 
1520   private boolean hasFoundUserPermission(UserPermission userPermission, List<UserPermission> perms) {
1521     return perms.contains(userPermission);
1522   }
1523 
1524   @Test (timeout=180000)
1525   public void testPostGrantRevokeAtQualifierLevel() throws Exception {
1526     final TableName tableName =
1527         TableName.valueOf("testGrantRevokeAtQualifierLevel");
1528     final byte[] family1 = Bytes.toBytes("f1");
1529     final byte[] family2 = Bytes.toBytes("f2");
1530     final byte[] qualifier = Bytes.toBytes("q");
1531 
1532     // create table
1533     Admin admin = TEST_UTIL.getHBaseAdmin();
1534     if (admin.tableExists(tableName)) {
1535       deleteTable(TEST_UTIL, tableName);
1536     }
1537     HTableDescriptor htd = new HTableDescriptor(tableName);
1538     htd.addFamily(new HColumnDescriptor(family1));
1539     htd.addFamily(new HColumnDescriptor(family2));
1540     createTable(TEST_UTIL, htd);
1541     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1542     try {
1543       // create temp users
1544       User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1545 
1546       AccessTestAction getQualifierAction = new AccessTestAction() {
1547         @Override
1548         public Object run() throws Exception {
1549           Get g = new Get(TEST_ROW);
1550           g.addColumn(family1, qualifier);
1551           try (Connection conn = ConnectionFactory.createConnection(conf);
1552               Table t = conn.getTable(tableName)) {
1553             t.get(g);
1554           }
1555           return null;
1556         }
1557       };
1558 
1559       AccessTestAction putQualifierAction = new AccessTestAction() {
1560         @Override
1561         public Object run() throws Exception {
1562           Put p = new Put(TEST_ROW);
1563           p.add(family1, qualifier, Bytes.toBytes("v1"));
1564           try (Connection conn = ConnectionFactory.createConnection(conf);
1565               Table t = conn.getTable(tableName)) {
1566             t.put(p);
1567           }
1568           return null;
1569         }
1570       };
1571 
1572       AccessTestAction deleteQualifierAction = new AccessTestAction() {
1573         @Override
1574         public Object run() throws Exception {
1575           Delete d = new Delete(TEST_ROW);
1576           d.deleteColumn(family1, qualifier);
1577           // d.deleteFamily(family1);
1578           try (Connection conn = ConnectionFactory.createConnection(conf);
1579               Table t = conn.getTable(tableName)) {
1580             t.delete(d);
1581           }
1582           return null;
1583         }
1584       };
1585 
1586       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, null);
1587 
1588       verifyDenied(user, getQualifierAction);
1589       verifyDenied(user, putQualifierAction);
1590       verifyDenied(user, deleteQualifierAction);
1591 
1592       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1593         Permission.Action.READ);
1594 
1595       verifyAllowed(user, getQualifierAction);
1596       verifyDenied(user, putQualifierAction);
1597       verifyDenied(user, deleteQualifierAction);
1598 
1599       // only grant write permission
1600       // TODO: comment this portion after HBASE-3583
1601       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1602         Permission.Action.WRITE);
1603 
1604       verifyDenied(user, getQualifierAction);
1605       verifyAllowed(user, putQualifierAction);
1606       verifyAllowed(user, deleteQualifierAction);
1607 
1608       // grant both read and write permission
1609       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1610         Permission.Action.READ, Permission.Action.WRITE);
1611 
1612       verifyAllowed(user, getQualifierAction);
1613       verifyAllowed(user, putQualifierAction);
1614       verifyAllowed(user, deleteQualifierAction);
1615 
1616       // revoke family level permission won't impact column level
1617       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier);
1618 
1619       verifyDenied(user, getQualifierAction);
1620       verifyDenied(user, putQualifierAction);
1621       verifyDenied(user, deleteQualifierAction);
1622     } finally {
1623       // delete table
1624       deleteTable(TEST_UTIL, tableName);
1625     }
1626   }
1627 
1628   @Test (timeout=180000)
1629   public void testPermissionList() throws Exception {
1630     final TableName tableName =
1631         TableName.valueOf("testPermissionList");
1632     final byte[] family1 = Bytes.toBytes("f1");
1633     final byte[] family2 = Bytes.toBytes("f2");
1634     final byte[] qualifier = Bytes.toBytes("q");
1635 
1636     // create table
1637     Admin admin = TEST_UTIL.getHBaseAdmin();
1638     if (admin.tableExists(tableName)) {
1639       deleteTable(TEST_UTIL, tableName);
1640     }
1641     HTableDescriptor htd = new HTableDescriptor(tableName);
1642     htd.addFamily(new HColumnDescriptor(family1));
1643     htd.addFamily(new HColumnDescriptor(family2));
1644     htd.setOwner(USER_OWNER);
1645     createTable(TEST_UTIL, htd);
1646     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
1647     try {
1648       List<UserPermission> perms;
1649       Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1650       try {
1651         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1652         AccessControlService.BlockingInterface protocol =
1653             AccessControlService.newBlockingStub(service);
1654         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1655       } finally {
1656         acl.close();
1657       }
1658 
1659       UserPermission ownerperm =
1660           new UserPermission(Bytes.toBytes(USER_OWNER.getName()), tableName, null, Action.values());
1661       assertTrue("Owner should have all permissions on table",
1662         hasFoundUserPermission(ownerperm, perms));
1663 
1664       User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1665       byte[] userName = Bytes.toBytes(user.getShortName());
1666 
1667       UserPermission up =
1668           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.READ);
1669       assertFalse("User should not be granted permission: " + up.toString(),
1670         hasFoundUserPermission(up, perms));
1671 
1672       // grant read permission
1673       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1674         Permission.Action.READ);
1675 
1676       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1677       try {
1678         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1679         AccessControlService.BlockingInterface protocol =
1680             AccessControlService.newBlockingStub(service);
1681         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1682       } finally {
1683         acl.close();
1684       }
1685 
1686       UserPermission upToVerify =
1687           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.READ);
1688       assertTrue("User should be granted permission: " + upToVerify.toString(),
1689         hasFoundUserPermission(upToVerify, perms));
1690 
1691       upToVerify =
1692           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.WRITE);
1693       assertFalse("User should not be granted permission: " + upToVerify.toString(),
1694         hasFoundUserPermission(upToVerify, perms));
1695 
1696       // grant read+write
1697       grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1698         Permission.Action.WRITE, Permission.Action.READ);
1699 
1700       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1701       try {
1702         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1703         AccessControlService.BlockingInterface protocol =
1704             AccessControlService.newBlockingStub(service);
1705         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1706       } finally {
1707         acl.close();
1708       }
1709 
1710       upToVerify =
1711           new UserPermission(userName, tableName, family1, qualifier, Permission.Action.WRITE,
1712               Permission.Action.READ);
1713       assertTrue("User should be granted permission: " + upToVerify.toString(),
1714         hasFoundUserPermission(upToVerify, perms));
1715 
1716       // revoke
1717       revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1718         Permission.Action.WRITE, Permission.Action.READ);
1719 
1720       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1721       try {
1722         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1723         AccessControlService.BlockingInterface protocol =
1724             AccessControlService.newBlockingStub(service);
1725         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1726       } finally {
1727         acl.close();
1728       }
1729 
1730       assertFalse("User should not be granted permission: " + upToVerify.toString(),
1731         hasFoundUserPermission(upToVerify, perms));
1732 
1733       // disable table before modification
1734       admin.disableTable(tableName);
1735 
1736       User newOwner = User.createUserForTesting(conf, "new_owner", new String[] {});
1737       htd.setOwner(newOwner);
1738       admin.modifyTable(tableName, htd);
1739 
1740       acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1741       try {
1742         BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1743         AccessControlService.BlockingInterface protocol =
1744             AccessControlService.newBlockingStub(service);
1745         perms = ProtobufUtil.getUserPermissions(null, protocol, tableName);
1746       } finally {
1747         acl.close();
1748       }
1749 
1750       UserPermission newOwnerperm =
1751           new UserPermission(Bytes.toBytes(newOwner.getName()), tableName, null, Action.values());
1752       assertTrue("New owner should have all permissions on table",
1753         hasFoundUserPermission(newOwnerperm, perms));
1754     } finally {
1755       // delete table
1756       deleteTable(TEST_UTIL, tableName);
1757     }
1758   }
1759 
1760   @Test (timeout=180000)
1761   public void testGlobalPermissionList() throws Exception {
1762     List<UserPermission> perms;
1763     Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1764     try {
1765       BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1766       AccessControlService.BlockingInterface protocol =
1767         AccessControlService.newBlockingStub(service);
1768       perms = ProtobufUtil.getUserPermissions(null, protocol);
1769     } finally {
1770       acl.close();
1771     }
1772     List<UserPermission> adminPerms = new ArrayList<UserPermission>();
1773     adminPerms.add(new UserPermission(Bytes.toBytes(USER_ADMIN.getShortName()),
1774       AccessControlLists.ACL_TABLE_NAME, null, null, Bytes.toBytes("ACRW")));
1775     List<String> superUsers = Superusers.getSuperUsers();
1776     for(String user: superUsers) {
1777       adminPerms.add(new UserPermission(Bytes.toBytes(user), AccessControlLists.ACL_TABLE_NAME,
1778           null, null, Action.values()));
1779     }
1780     assertTrue("Only super users, global users and user admin has permission on table hbase:acl " +
1781         "per setup", perms.size() == 5 + superUsers.size() &&
1782         hasFoundUserPermission(adminPerms, perms));
1783   }
1784 
1785   /** global operations */
1786   private void verifyGlobal(AccessTestAction action) throws Exception {
1787     verifyAllowed(action, SUPERUSER);
1788 
1789     verifyDenied(action, USER_CREATE, USER_RW, USER_NONE, USER_RO);
1790   }
1791 
1792   @Test (timeout=180000)
1793   public void testCheckPermissions() throws Exception {
1794     // --------------------------------------
1795     // test global permissions
1796     AccessTestAction globalAdmin = new AccessTestAction() {
1797       @Override
1798       public Void run() throws Exception {
1799         checkGlobalPerms(TEST_UTIL, Permission.Action.ADMIN);
1800         return null;
1801       }
1802     };
1803     // verify that only superuser can admin
1804     verifyGlobal(globalAdmin);
1805 
1806     // --------------------------------------
1807     // test multiple permissions
1808     AccessTestAction globalReadWrite = new AccessTestAction() {
1809       @Override
1810       public Void run() throws Exception {
1811         checkGlobalPerms(TEST_UTIL, Permission.Action.READ, Permission.Action.WRITE);
1812         return null;
1813       }
1814     };
1815 
1816     verifyGlobal(globalReadWrite);
1817 
1818     // --------------------------------------
1819     // table/column/qualifier level permissions
1820     final byte[] TEST_Q1 = Bytes.toBytes("q1");
1821     final byte[] TEST_Q2 = Bytes.toBytes("q2");
1822 
1823     User userTable = User.createUserForTesting(conf, "user_check_perms_table", new String[0]);
1824     User userColumn = User.createUserForTesting(conf, "user_check_perms_family", new String[0]);
1825     User userQualifier = User.createUserForTesting(conf, "user_check_perms_q", new String[0]);
1826 
1827     grantOnTable(TEST_UTIL, userTable.getShortName(),
1828       TEST_TABLE, null, null,
1829       Permission.Action.READ);
1830     grantOnTable(TEST_UTIL, userColumn.getShortName(),
1831       TEST_TABLE, TEST_FAMILY, null,
1832       Permission.Action.READ);
1833     grantOnTable(TEST_UTIL, userQualifier.getShortName(),
1834       TEST_TABLE, TEST_FAMILY, TEST_Q1,
1835       Permission.Action.READ);
1836 
1837     try {
1838       AccessTestAction tableRead = new AccessTestAction() {
1839         @Override
1840         public Void run() throws Exception {
1841           checkTablePerms(TEST_UTIL, TEST_TABLE, null, null, Permission.Action.READ);
1842           return null;
1843         }
1844       };
1845 
1846       AccessTestAction columnRead = new AccessTestAction() {
1847         @Override
1848         public Void run() throws Exception {
1849           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ);
1850           return null;
1851         }
1852       };
1853 
1854       AccessTestAction qualifierRead = new AccessTestAction() {
1855         @Override
1856         public Void run() throws Exception {
1857           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1858           return null;
1859         }
1860       };
1861 
1862       AccessTestAction multiQualifierRead = new AccessTestAction() {
1863         @Override
1864         public Void run() throws Exception {
1865           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] {
1866               new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ),
1867               new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q2, Permission.Action.READ), });
1868           return null;
1869         }
1870       };
1871 
1872       AccessTestAction globalAndTableRead = new AccessTestAction() {
1873         @Override
1874         public Void run() throws Exception {
1875           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] {
1876               new Permission(Permission.Action.READ),
1877               new TablePermission(TEST_TABLE, null, (byte[]) null, Permission.Action.READ), });
1878           return null;
1879         }
1880       };
1881 
1882       AccessTestAction noCheck = new AccessTestAction() {
1883         @Override
1884         public Void run() throws Exception {
1885           checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[0]);
1886           return null;
1887         }
1888       };
1889 
1890       verifyAllowed(tableRead, SUPERUSER, userTable);
1891       verifyDenied(tableRead, userColumn, userQualifier);
1892 
1893       verifyAllowed(columnRead, SUPERUSER, userTable, userColumn);
1894       verifyDenied(columnRead, userQualifier);
1895 
1896       verifyAllowed(qualifierRead, SUPERUSER, userTable, userColumn, userQualifier);
1897 
1898       verifyAllowed(multiQualifierRead, SUPERUSER, userTable, userColumn);
1899       verifyDenied(multiQualifierRead, userQualifier);
1900 
1901       verifyAllowed(globalAndTableRead, SUPERUSER);
1902       verifyDenied(globalAndTableRead, userTable, userColumn, userQualifier);
1903 
1904       verifyAllowed(noCheck, SUPERUSER, userTable, userColumn, userQualifier);
1905 
1906       // --------------------------------------
1907       // test family level multiple permissions
1908       AccessTestAction familyReadWrite = new AccessTestAction() {
1909         @Override
1910         public Void run() throws Exception {
1911           checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ,
1912             Permission.Action.WRITE);
1913           return null;
1914         }
1915       };
1916 
1917       verifyAllowed(familyReadWrite, SUPERUSER, USER_OWNER, USER_CREATE, USER_RW);
1918       verifyDenied(familyReadWrite, USER_NONE, USER_RO);
1919 
1920       // --------------------------------------
1921       // check for wrong table region
1922       CheckPermissionsRequest checkRequest =
1923           CheckPermissionsRequest
1924               .newBuilder()
1925               .addPermission(
1926                 AccessControlProtos.Permission
1927                     .newBuilder()
1928                     .setType(AccessControlProtos.Permission.Type.Table)
1929                     .setTablePermission(
1930                       AccessControlProtos.TablePermission.newBuilder()
1931                           .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE))
1932                           .addAction(AccessControlProtos.Permission.Action.CREATE))).build();
1933       Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME);
1934       try {
1935         BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1936         AccessControlService.BlockingInterface protocol =
1937             AccessControlService.newBlockingStub(channel);
1938         try {
1939           // but ask for TablePermissions for TEST_TABLE
1940           protocol.checkPermissions(null, checkRequest);
1941           fail("this should have thrown CoprocessorException");
1942         } catch (ServiceException ex) {
1943           // expected
1944         }
1945       } finally {
1946         acl.close();
1947       }
1948 
1949     } finally {
1950       revokeFromTable(TEST_UTIL, userTable.getShortName(), TEST_TABLE, null, null,
1951         Permission.Action.READ);
1952       revokeFromTable(TEST_UTIL, userColumn.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1953         Permission.Action.READ);
1954       revokeFromTable(TEST_UTIL, userQualifier.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_Q1,
1955         Permission.Action.READ);
1956     }
1957   }
1958 
1959   @Test (timeout=180000)
1960   public void testStopRegionServer() throws Exception {
1961     AccessTestAction action = new AccessTestAction() {
1962       @Override
1963       public Object run() throws Exception {
1964         ACCESS_CONTROLLER.preStopRegionServer(ObserverContext.createAndPrepare(RSCP_ENV, null));
1965         return null;
1966       }
1967     };
1968 
1969     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1970     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1971       USER_GROUP_WRITE, USER_GROUP_CREATE);
1972   }
1973 
1974   @Test (timeout=180000)
1975   public void testRollWALWriterRequest() throws Exception {
1976     AccessTestAction action = new AccessTestAction() {
1977       @Override
1978       public Object run() throws Exception {
1979         ACCESS_CONTROLLER.preRollWALWriterRequest(ObserverContext.createAndPrepare(RSCP_ENV, null));
1980         return null;
1981       }
1982     };
1983 
1984     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1985     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1986       USER_GROUP_WRITE, USER_GROUP_CREATE);
1987   }
1988 
1989   @Test (timeout=180000)
1990   public void testOpenRegion() throws Exception {
1991     AccessTestAction action = new AccessTestAction() {
1992       @Override
1993       public Object run() throws Exception {
1994         ACCESS_CONTROLLER.preOpen(ObserverContext.createAndPrepare(RCP_ENV, null));
1995         return null;
1996       }
1997     };
1998 
1999     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2000     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2001       USER_GROUP_READ, USER_GROUP_WRITE);
2002   }
2003 
2004   @Test (timeout=180000)
2005   public void testCloseRegion() throws Exception {
2006     AccessTestAction action = new AccessTestAction() {
2007       @Override
2008       public Object run() throws Exception {
2009         ACCESS_CONTROLLER.preClose(ObserverContext.createAndPrepare(RCP_ENV, null), false);
2010         return null;
2011       }
2012     };
2013 
2014     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2015     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2016       USER_GROUP_READ, USER_GROUP_WRITE);
2017   }
2018 
2019   @Test (timeout=180000)
2020   public void testSnapshot() throws Exception {
2021     Admin admin = TEST_UTIL.getHBaseAdmin();
2022     final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE);
2023     SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
2024     builder.setName(TEST_TABLE.getNameAsString() + "-snapshot");
2025     builder.setTable(TEST_TABLE.getNameAsString());
2026     final SnapshotDescription snapshot = builder.build();
2027     AccessTestAction snapshotAction = new AccessTestAction() {
2028       @Override
2029       public Object run() throws Exception {
2030         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2031           snapshot, htd);
2032         return null;
2033       }
2034     };
2035 
2036     AccessTestAction deleteAction = new AccessTestAction() {
2037       @Override
2038       public Object run() throws Exception {
2039         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2040           snapshot);
2041         return null;
2042       }
2043     };
2044 
2045     AccessTestAction restoreAction = new AccessTestAction() {
2046       @Override
2047       public Object run() throws Exception {
2048         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2049           snapshot, htd);
2050         return null;
2051       }
2052     };
2053 
2054     AccessTestAction cloneAction = new AccessTestAction() {
2055       @Override
2056       public Object run() throws Exception {
2057         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2058           snapshot, null);
2059         return null;
2060       }
2061     };
2062 
2063     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2064     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2065       USER_GROUP_WRITE, USER_GROUP_CREATE);
2066 
2067     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2068     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2069       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2070 
2071     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2072     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2073       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2074 
2075     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2076     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2077       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2078   }
2079 
2080   @Test (timeout=180000)
2081   public void testSnapshotWithOwner() throws Exception {
2082     Admin admin = TEST_UTIL.getHBaseAdmin();
2083     final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE);
2084     SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
2085     builder.setName(TEST_TABLE.getNameAsString() + "-snapshot");
2086     builder.setTable(TEST_TABLE.getNameAsString());
2087     builder.setOwner(USER_OWNER.getName());
2088     final SnapshotDescription snapshot = builder.build();
2089     AccessTestAction snapshotAction = new AccessTestAction() {
2090       @Override
2091       public Object run() throws Exception {
2092         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2093           snapshot, htd);
2094         return null;
2095       }
2096     };
2097     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2098     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2099       USER_GROUP_WRITE, USER_GROUP_CREATE);
2100 
2101     AccessTestAction deleteAction = new AccessTestAction() {
2102       @Override
2103       public Object run() throws Exception {
2104         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2105           snapshot);
2106         return null;
2107       }
2108     };
2109     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2110     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2111       USER_GROUP_WRITE, USER_GROUP_CREATE);
2112 
2113     AccessTestAction restoreAction = new AccessTestAction() {
2114       @Override
2115       public Object run() throws Exception {
2116         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2117           snapshot, htd);
2118         return null;
2119       }
2120     };
2121     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2122     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2123       USER_GROUP_WRITE, USER_GROUP_CREATE);
2124 
2125     AccessTestAction cloneAction = new AccessTestAction() {
2126       @Override
2127       public Object run() throws Exception {
2128         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
2129           snapshot, null);
2130         return null;
2131       }
2132     };
2133     // Clone by snapshot owner is not allowed , because clone operation creates a new table,
2134     // which needs global admin permission.
2135     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2136     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2137       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2138   }
2139 
2140   @Test (timeout=180000)
2141   public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
2142     LOG.debug("Test for global authorization for a new registered RegionServer.");
2143     MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
2144 
2145     final Admin admin = TEST_UTIL.getHBaseAdmin();
2146     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE2);
2147     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
2148     createTable(TEST_UTIL, htd);
2149     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2150 
2151     // Starting a new RegionServer.
2152     JVMClusterUtil.RegionServerThread newRsThread = hbaseCluster
2153         .startRegionServer();
2154     final HRegionServer newRs = newRsThread.getRegionServer();
2155 
2156     // Move region to the new RegionServer.
2157     List<HRegionLocation> regions;
2158     try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE2)) {
2159       regions = locator.getAllRegionLocations();
2160     }
2161     HRegionLocation location = regions.get(0);
2162     final HRegionInfo hri = location.getRegionInfo();
2163     final ServerName server = location.getServerName();
2164     try (HTable table = (HTable) systemUserConnection.getTable(TEST_TABLE2)) {
2165       AccessTestAction moveAction = new AccessTestAction() {
2166         @Override
2167         public Object run() throws Exception {
2168           admin.move(hri.getEncodedNameAsBytes(),
2169             Bytes.toBytes(newRs.getServerName().getServerName()));
2170           return null;
2171         }
2172       };
2173       SUPERUSER.runAs(moveAction);
2174 
2175       final int RETRIES_LIMIT = 10;
2176       int retries = 0;
2177       while (newRs.getOnlineRegions(TEST_TABLE2).size() < 1 && retries < RETRIES_LIMIT) {
2178         LOG.debug("Waiting for region to be opened. Already retried " + retries
2179             + " times.");
2180         try {
2181           Thread.sleep(1000);
2182         } catch (InterruptedException e) {
2183         }
2184         retries++;
2185         if (retries == RETRIES_LIMIT - 1) {
2186           fail("Retry exhaust for waiting region to be opened.");
2187         }
2188       }
2189       // Verify write permission for user "admin2" who has the global
2190       // permissions.
2191       AccessTestAction putAction = new AccessTestAction() {
2192         @Override
2193         public Object run() throws Exception {
2194           Put put = new Put(Bytes.toBytes("test"));
2195           put.add(TEST_FAMILY, Bytes.toBytes("qual"), Bytes.toBytes("value"));
2196           table.put(put);
2197           return null;
2198         }
2199       };
2200       USER_ADMIN.runAs(putAction);
2201     }
2202   }
2203 
2204   @Test (timeout=180000)
2205   public void testTableDescriptorsEnumeration() throws Exception {
2206     User TABLE_ADMIN = User.createUserForTesting(conf, "UserA", new String[0]);
2207 
2208     // Grant TABLE ADMIN privs
2209     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2210       Permission.Action.ADMIN);
2211     try {
2212       AccessTestAction listTablesAction = new AccessTestAction() {
2213         @Override
2214         public Object run() throws Exception {
2215           try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2216               Admin admin = conn.getAdmin()) {
2217             return Arrays.asList(admin.listTables());
2218           }
2219         }
2220       };
2221 
2222       AccessTestAction getTableDescAction = new AccessTestAction() {
2223         @Override
2224         public Object run() throws Exception {
2225           try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2226               Admin admin = conn.getAdmin();) {
2227             return admin.getTableDescriptor(TEST_TABLE);
2228           }
2229         }
2230       };
2231 
2232       verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, TABLE_ADMIN,
2233         USER_GROUP_CREATE, USER_GROUP_ADMIN);
2234       verifyIfEmptyList(listTablesAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2235         USER_GROUP_WRITE);
2236 
2237       verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER,
2238         TABLE_ADMIN, USER_GROUP_CREATE, USER_GROUP_ADMIN);
2239       verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2240         USER_GROUP_WRITE);
2241     } finally {
2242       // Cleanup, revoke TABLE ADMIN privs
2243       revokeFromTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2244         Permission.Action.ADMIN);
2245     }
2246   }
2247 
2248   @Test (timeout=180000)
2249   public void testTableNameEnumeration() throws Exception {
2250     AccessTestAction listTablesAction = new AccessTestAction() {
2251       @Override
2252       public Object run() throws Exception {
2253         Connection unmanagedConnection =
2254             ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2255         Admin admin = unmanagedConnection.getAdmin();
2256         try {
2257           return Arrays.asList(admin.listTableNames());
2258         } finally {
2259           admin.close();
2260           unmanagedConnection.close();
2261         }
2262       }
2263     };
2264 
2265     verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW,
2266       USER_RO, USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_WRITE);
2267     verifyIfEmptyList(listTablesAction, USER_NONE);
2268   }
2269 
2270   @Test (timeout=180000)
2271   public void testTableDeletion() throws Exception {
2272     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
2273     final TableName tname = TableName.valueOf("testTableDeletion");
2274     createTestTable(tname);
2275 
2276     // Grant TABLE ADMIN privs
2277     grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), tname, null, null, Permission.Action.ADMIN);
2278 
2279     AccessTestAction deleteTableAction = new AccessTestAction() {
2280       @Override
2281       public Object run() throws Exception {
2282         Connection unmanagedConnection =
2283             ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2284         Admin admin = unmanagedConnection.getAdmin();
2285         try {
2286           deleteTable(TEST_UTIL, admin, tname);
2287         } finally {
2288           admin.close();
2289           unmanagedConnection.close();
2290         }
2291         return null;
2292       }
2293     };
2294 
2295     verifyDenied(deleteTableAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2296       USER_GROUP_WRITE);
2297     verifyAllowed(deleteTableAction, TABLE_ADMIN);
2298   }
2299 
2300   private void createTestTable(TableName tname) throws Exception {
2301     HTableDescriptor htd = new HTableDescriptor(tname);
2302     HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
2303     hcd.setMaxVersions(100);
2304     htd.addFamily(hcd);
2305     htd.setOwner(USER_OWNER);
2306     createTable(TEST_UTIL, htd, new byte[][]{Bytes.toBytes("s")});
2307     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2308   }
2309 
2310   @Test (timeout=180000)
2311   public void testNamespaceUserGrant() throws Exception {
2312     AccessTestAction getAction = new AccessTestAction() {
2313       @Override
2314       public Object run() throws Exception {
2315         try(Connection conn = ConnectionFactory.createConnection(conf);
2316             Table t = conn.getTable(TEST_TABLE);) {
2317           return t.get(new Get(TEST_ROW));
2318         }
2319       }
2320     };
2321 
2322     String namespace = TEST_TABLE.getNamespaceAsString();
2323 
2324     // Grant namespace READ to USER_NONE, this should supersede any table permissions
2325     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2326     // Now USER_NONE should be able to read
2327     verifyAllowed(getAction, USER_NONE);
2328 
2329     // Revoke namespace READ to USER_NONE
2330     revokeFromNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2331     verifyDenied(getAction, USER_NONE);
2332   }
2333 
2334   @Test (timeout=180000)
2335   public void testAccessControlClientGrantRevoke() throws Exception {
2336     // Create user for testing, who has no READ privileges by default.
2337     User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2338     AccessTestAction getAction = new AccessTestAction() {
2339       @Override
2340       public Object run() throws Exception {
2341         try(Connection conn = ConnectionFactory.createConnection(conf);
2342             Table t = conn.getTable(TEST_TABLE);) {
2343           return t.get(new Get(TEST_ROW));
2344         }
2345       }
2346     };
2347 
2348     verifyDenied(getAction, testGrantRevoke);
2349 
2350     // Grant table READ permissions to testGrantRevoke.
2351     try {
2352       grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2353         testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2354     } catch (Throwable e) {
2355       LOG.error("error during call of AccessControlClient.grant. ", e);
2356     }
2357 
2358     // Now testGrantRevoke should be able to read also
2359     verifyAllowed(getAction, testGrantRevoke);
2360 
2361     // Revoke table READ permission to testGrantRevoke.
2362     try {
2363       revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2364         testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2365     } catch (Throwable e) {
2366       LOG.error("error during call of AccessControlClient.revoke ", e);
2367     }
2368 
2369     // Now testGrantRevoke shouldn't be able read
2370     verifyDenied(getAction, testGrantRevoke);
2371   }
2372 
2373   @Test (timeout=180000)
2374   public void testAccessControlClientGlobalGrantRevoke() throws Exception {
2375     // Create user for testing, who has no READ privileges by default.
2376     User testGlobalGrantRevoke = User.createUserForTesting(conf,
2377       "testGlobalGrantRevoke", new String[0]);
2378     AccessTestAction getAction = new AccessTestAction() {
2379       @Override
2380       public Object run() throws Exception {
2381         try(Connection conn = ConnectionFactory.createConnection(conf);
2382             Table t = conn.getTable(TEST_TABLE)) {
2383           return t.get(new Get(TEST_ROW));
2384         }
2385       }
2386     };
2387 
2388     verifyDenied(getAction, testGlobalGrantRevoke);
2389 
2390     // Grant table READ permissions to testGlobalGrantRevoke.
2391     String userName = testGlobalGrantRevoke.getShortName();
2392     try {
2393       grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2394         Permission.Action.READ);
2395     } catch (Throwable e) {
2396       LOG.error("error during call of AccessControlClient.grant. ", e);
2397     }
2398     try {
2399       // Now testGlobalGrantRevoke should be able to read also
2400       verifyAllowed(getAction, testGlobalGrantRevoke);
2401     } catch (Exception e) {
2402       revokeGlobal(TEST_UTIL, userName, Permission.Action.READ);
2403       throw e;
2404     }
2405 
2406     // Revoke table READ permission to testGlobalGrantRevoke.
2407     try {
2408       revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2409         Permission.Action.READ);
2410     } catch (Throwable e) {
2411       LOG.error("error during call of AccessControlClient.revoke ", e);
2412     }
2413 
2414     // Now testGlobalGrantRevoke shouldn't be able read
2415     verifyDenied(getAction, testGlobalGrantRevoke);
2416 
2417   }
2418 
2419   @Test (timeout=180000)
2420   public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
2421     // Create user for testing, who has no READ privileges by default.
2422     User testNS = User.createUserForTesting(conf, "testNS", new String[0]);
2423     AccessTestAction getAction = new AccessTestAction() {
2424       @Override
2425       public Object run() throws Exception {
2426         try(Connection conn = ConnectionFactory.createConnection(conf);
2427             Table t = conn.getTable(TEST_TABLE);) {
2428           return t.get(new Get(TEST_ROW));
2429         }
2430       }
2431     };
2432 
2433     verifyDenied(getAction, testNS);
2434 
2435     String userName = testNS.getShortName();
2436     String namespace = TEST_TABLE.getNamespaceAsString();
2437     // Grant namespace READ to testNS, this should supersede any table permissions
2438     try {
2439       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, namespace,
2440         Permission.Action.READ);
2441     } catch (Throwable e) {
2442       LOG.error("error during call of AccessControlClient.grant. ", e);
2443     }
2444     try {
2445       // Now testNS should be able to read also
2446       verifyAllowed(getAction, testNS);
2447     } catch (Exception e) {
2448       revokeFromNamespace(TEST_UTIL, userName, namespace, Permission.Action.READ);
2449       throw e;
2450     }
2451 
2452     // Revoke namespace READ to testNS, this should supersede any table permissions
2453     try {
2454       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2455         namespace, Permission.Action.READ);
2456     } catch (Throwable e) {
2457       LOG.error("error during call of AccessControlClient.revoke ", e);
2458     }
2459 
2460     // Now testNS shouldn't be able read
2461     verifyDenied(getAction, testNS);
2462   }
2463 
2464 
2465   public static class PingCoprocessor extends PingService implements Coprocessor,
2466       CoprocessorService {
2467 
2468     @Override
2469     public void start(CoprocessorEnvironment env) throws IOException { }
2470 
2471     @Override
2472     public void stop(CoprocessorEnvironment env) throws IOException { }
2473 
2474     @Override
2475     public Service getService() {
2476       return this;
2477     }
2478 
2479     @Override
2480     public void ping(RpcController controller, PingRequest request,
2481         RpcCallback<PingResponse> callback) {
2482       callback.run(PingResponse.newBuilder().setPong("Pong!").build());
2483     }
2484 
2485     @Override
2486     public void count(RpcController controller, CountRequest request,
2487         RpcCallback<CountResponse> callback) {
2488       callback.run(CountResponse.newBuilder().build());
2489     }
2490 
2491     @Override
2492     public void increment(RpcController controller, IncrementCountRequest requet,
2493         RpcCallback<IncrementCountResponse> callback) {
2494       callback.run(IncrementCountResponse.newBuilder().build());
2495     }
2496 
2497     @Override
2498     public void hello(RpcController controller, HelloRequest request,
2499         RpcCallback<HelloResponse> callback) {
2500       callback.run(HelloResponse.newBuilder().setResponse("Hello!").build());
2501     }
2502 
2503     @Override
2504     public void noop(RpcController controller, NoopRequest request,
2505         RpcCallback<NoopResponse> callback) {
2506       callback.run(NoopResponse.newBuilder().build());
2507     }
2508   }
2509 
2510   @Test (timeout=180000)
2511   public void testCoprocessorExec() throws Exception {
2512     // Set up our ping endpoint service on all regions of our test table
2513     for (JVMClusterUtil.RegionServerThread thread:
2514         TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
2515       HRegionServer rs = thread.getRegionServer();
2516       for (Region region: rs.getOnlineRegions(TEST_TABLE)) {
2517         region.getCoprocessorHost().load(PingCoprocessor.class,
2518           Coprocessor.PRIORITY_USER, conf);
2519       }
2520     }
2521 
2522     // Create users for testing, and grant EXEC privileges on our test table
2523     // only to user A
2524     User userA = User.createUserForTesting(conf, "UserA", new String[0]);
2525     User userB = User.createUserForTesting(conf, "UserB", new String[0]);
2526 
2527     grantOnTable(TEST_UTIL, userA.getShortName(),
2528       TEST_TABLE, null, null,
2529       Permission.Action.EXEC);
2530     try {
2531       // Create an action for invoking our test endpoint
2532       AccessTestAction execEndpointAction = new AccessTestAction() {
2533         @Override
2534         public Object run() throws Exception {
2535           try (Connection conn = ConnectionFactory.createConnection(conf);
2536               Table t = conn.getTable(TEST_TABLE);) {
2537             BlockingRpcChannel service = t.coprocessorService(HConstants.EMPTY_BYTE_ARRAY);
2538             PingCoprocessor.newBlockingStub(service).noop(null, NoopRequest.newBuilder().build());
2539           }
2540           return null;
2541         }
2542       };
2543 
2544       String namespace = TEST_TABLE.getNamespaceAsString();
2545       // Now grant EXEC to the entire namespace to user B
2546       grantOnNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2547       // User B should now be allowed also
2548       verifyAllowed(execEndpointAction, userA, userB);
2549 
2550       revokeFromNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2551       // Verify that EXEC permission is checked correctly
2552       verifyDenied(execEndpointAction, userB);
2553       verifyAllowed(execEndpointAction, userA);
2554     } finally {
2555       // Cleanup, revoke the userA privileges
2556       revokeFromTable(TEST_UTIL, userA.getShortName(), TEST_TABLE, null, null,
2557         Permission.Action.EXEC);
2558     }
2559   }
2560 
2561   @Test (timeout=180000)
2562   public void testSetQuota() throws Exception {
2563     AccessTestAction setUserQuotaAction = new AccessTestAction() {
2564       @Override
2565       public Object run() throws Exception {
2566         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2567           null, null);
2568         return null;
2569       }
2570     };
2571 
2572     AccessTestAction setUserTableQuotaAction = new AccessTestAction() {
2573       @Override
2574       public Object run() throws Exception {
2575         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null), null,
2576           TEST_TABLE, null);
2577         return null;
2578       }
2579     };
2580 
2581     AccessTestAction setUserNamespaceQuotaAction = new AccessTestAction() {
2582       @Override
2583       public Object run() throws Exception {
2584         ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2585           null, (String)null, null);
2586         return null;
2587       }
2588     };
2589 
2590     AccessTestAction setTableQuotaAction = new AccessTestAction() {
2591       @Override
2592       public Object run() throws Exception {
2593         ACCESS_CONTROLLER.preSetTableQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2594           TEST_TABLE, null);
2595         return null;
2596       }
2597     };
2598 
2599     AccessTestAction setNamespaceQuotaAction = new AccessTestAction() {
2600       @Override
2601       public Object run() throws Exception {
2602         ACCESS_CONTROLLER.preSetNamespaceQuota(ObserverContext.createAndPrepare(CP_ENV, null),
2603           null, null);
2604         return null;
2605       }
2606     };
2607 
2608     verifyAllowed(setUserQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2609     verifyDenied(setUserQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2610       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2611 
2612     verifyAllowed(setUserTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2613     verifyDenied(setUserTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE,
2614       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2615 
2616     verifyAllowed(setUserNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2617     verifyDenied(setUserNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2618       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2619 
2620     verifyAllowed(setTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2621     verifyDenied(setTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
2622 
2623     verifyAllowed(setNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2624     verifyDenied(setNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2625       USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2626   }
2627 
2628   @Test (timeout=180000)
2629   public void testGetNamespacePermission() throws Exception {
2630     String namespace = "testGetNamespacePermission";
2631     NamespaceDescriptor desc = NamespaceDescriptor.create(namespace).build();
2632     createNamespace(TEST_UTIL, desc);
2633     grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2634 
2635     // Test 1: A specific namespace
2636     getNamespacePermissionsAndVerify(namespace, 1, namespace);
2637 
2638     // Test 2: '@.*'
2639     getNamespacePermissionsAndVerify(".*", 1, namespace);
2640 
2641     // Test 3: A more complex regex
2642     getNamespacePermissionsAndVerify("^test[a-zA-Z]*", 1, namespace);
2643 
2644     deleteNamespace(TEST_UTIL, namespace);
2645   }
2646 
2647   /**
2648    * List all user permissions match the given regular expression for namespace
2649    * and verify each of them.
2650    * @param namespaceRegexWithoutPrefix the regualar expression for namespace, without NAMESPACE_PREFIX
2651    * @param expectedAmount the expected amount of user permissions returned
2652    * @param expectedNamespace the expected namespace of each user permission returned
2653    * @throws HBaseException in the case of any HBase exception when accessing hbase:acl table
2654    */
2655   private void getNamespacePermissionsAndVerify(String namespaceRegexWithoutPrefix,
2656       int expectedAmount, String expectedNamespace) throws HBaseException {
2657     try {
2658       List<UserPermission> namespacePermissions = AccessControlClient.getUserPermissions(
2659         systemUserConnection, AccessControlLists.toNamespaceEntry(namespaceRegexWithoutPrefix));
2660       assertTrue(namespacePermissions != null);
2661       assertEquals(expectedAmount, namespacePermissions.size());
2662       for (UserPermission namespacePermission : namespacePermissions) {
2663         assertFalse(namespacePermission.isGlobal());  // Verify it is not a global user permission
2664         assertEquals(expectedNamespace, namespacePermission.getNamespace());  // Verify namespace is set
2665       }
2666     } catch (Throwable thw) {
2667       throw new HBaseException(thw);
2668     }
2669   }
2670 
2671   @Test (timeout=180000)
2672   public void testTruncatePerms() throws Exception {
2673     try {
2674       List<UserPermission> existingPerms = AccessControlClient.getUserPermissions(
2675           systemUserConnection, TEST_TABLE.getNameAsString());
2676       assertTrue(existingPerms != null);
2677       assertTrue(existingPerms.size() > 1);
2678       TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE);
2679       TEST_UTIL.truncateTable(TEST_TABLE);
2680       TEST_UTIL.waitTableAvailable(TEST_TABLE);
2681       List<UserPermission> perms = AccessControlClient.getUserPermissions(
2682           systemUserConnection, TEST_TABLE.getNameAsString());
2683       assertTrue(perms != null);
2684       assertEquals(existingPerms.size(), perms.size());
2685     } catch (Throwable e) {
2686       throw new HBaseIOException(e);
2687     }
2688   }
2689 
2690   private PrivilegedAction<List<UserPermission>> getPrivilegedAction(final String regex) {
2691     return new PrivilegedAction<List<UserPermission>>() {
2692       @Override
2693       public List<UserPermission> run() {
2694         try(Connection conn = ConnectionFactory.createConnection(conf);) {
2695           return AccessControlClient.getUserPermissions(conn, regex);
2696         } catch (Throwable e) {
2697           LOG.error("error during call of AccessControlClient.getUserPermissions.", e);
2698           return null;
2699         }
2700       }
2701     };
2702   }
2703 
2704   @Test (timeout=180000)
2705   public void testAccessControlClientUserPerms() throws Exception {
2706     TableName tname = TableName.valueOf("testAccessControlClientUserPerms");
2707     createTestTable(tname);
2708     try {
2709       final String regex = tname.getNameWithNamespaceInclAsString();
2710       User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new String[0]);
2711       assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
2712       // Grant TABLE ADMIN privs to testUserPerms
2713       grantOnTable(TEST_UTIL, testUserPerms.getShortName(), tname, null, null, Action.ADMIN);
2714       List<UserPermission> perms = testUserPerms.runAs(getPrivilegedAction(regex));
2715       assertNotNull(perms);
2716       // Superuser, testUserPerms
2717       assertEquals(2, perms.size());
2718     } finally {
2719       deleteTable(TEST_UTIL, tname);
2720     }
2721   }
2722 
2723   @Test (timeout=180000)
2724   public void testAccessControllerUserPermsRegexHandling() throws Exception {
2725     User testRegexHandler = User.createUserForTesting(conf, "testRegexHandling", new String[0]);
2726 
2727     final String REGEX_ALL_TABLES = ".*";
2728     final String tableName = "testRegex";
2729     final TableName table1 = TableName.valueOf(tableName);
2730     final byte[] family = Bytes.toBytes("f1");
2731 
2732     // create table in default ns
2733     Admin admin = TEST_UTIL.getHBaseAdmin();
2734     HTableDescriptor htd = new HTableDescriptor(table1);
2735     htd.addFamily(new HColumnDescriptor(family));
2736     createTable(TEST_UTIL, htd);
2737     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2738 
2739     // creating the ns and table in it
2740     String ns = "testNamespace";
2741     NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
2742     final TableName table2 = TableName.valueOf(ns, tableName);
2743     createNamespace(TEST_UTIL, desc);
2744     htd = new HTableDescriptor(table2);
2745     htd.addFamily(new HColumnDescriptor(family));
2746     createTable(TEST_UTIL, htd);
2747     TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
2748 
2749     // Verify that we can read sys-tables
2750     String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString();
2751     assertEquals(5, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
2752     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
2753 
2754     // Grant TABLE ADMIN privs to testUserPerms
2755     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2756     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, null, Action.ADMIN);
2757     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2758     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, null, Action.ADMIN);
2759     assertEquals(4, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2760 
2761     // USER_ADMIN, testUserPerms must have a row each.
2762     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
2763     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
2764           NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + TableName.NAMESPACE_DELIM + tableName)
2765         ).size());
2766     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
2767         ns + TableName.NAMESPACE_DELIM + tableName)).size());
2768     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
2769 
2770     deleteTable(TEST_UTIL, table1);
2771     deleteTable(TEST_UTIL, table2);
2772     deleteNamespace(TEST_UTIL, ns);
2773   }
2774 
2775   private void verifyAnyCreate(AccessTestAction action) throws Exception {
2776     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_ADMIN_CF,
2777       USER_GROUP_CREATE);
2778     verifyDenied(action, USER_NONE, USER_RO, USER_RW, USER_GROUP_READ, USER_GROUP_WRITE,
2779       USER_GROUP_ADMIN);
2780   }
2781 
2782   @Test (timeout=180000)
2783   public void testPrepareAndCleanBulkLoad() throws Exception {
2784     AccessTestAction prepareBulkLoadAction = new AccessTestAction() {
2785       @Override
2786       public Object run() throws Exception {
2787         ACCESS_CONTROLLER.prePrepareBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
2788           null);
2789         return null;
2790       }
2791     };
2792     AccessTestAction cleanupBulkLoadAction = new AccessTestAction() {
2793       @Override
2794       public Object run() throws Exception {
2795         ACCESS_CONTROLLER.preCleanupBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
2796           null);
2797         return null;
2798       }
2799     };
2800     verifyAnyCreate(prepareBulkLoadAction);
2801     verifyAnyCreate(cleanupBulkLoadAction);
2802   }
2803 
2804   @Test (timeout=180000)
2805   public void testReplicateLogEntries() throws Exception {
2806     AccessTestAction replicateLogEntriesAction = new AccessTestAction() {
2807       @Override
2808       public Object run() throws Exception {
2809         ACCESS_CONTROLLER.preReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2810           null, null);
2811         ACCESS_CONTROLLER.postReplicateLogEntries(ObserverContext.createAndPrepare(RSCP_ENV, null),
2812           null, null);
2813         return null;
2814       }
2815     };
2816 
2817     verifyAllowed(replicateLogEntriesAction, SUPERUSER, USER_ADMIN, USER_GROUP_WRITE);
2818     verifyDenied(replicateLogEntriesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2819       USER_GROUP_READ, USER_GROUP_ADMIN, USER_GROUP_CREATE);
2820   }
2821 
2822   @Test
2823   public void testAccessControlRevokeOnlyFewPermission() throws Throwable {
2824     TableName tname = TableName.valueOf("revoke");
2825     try {
2826       TEST_UTIL.createTable(tname, TEST_FAMILY);
2827       TEST_UTIL.waitUntilAllRegionsAssigned(tname);
2828 
2829       User testUserPerms = User.createUserForTesting(conf, "revokePerms", new String[0]);
2830       Permission.Action[] actions = { Action.READ, Action.WRITE };
2831       AccessControlClient.grant(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
2832         null, null, actions);
2833 
2834       List<UserPermission> userPermissions = AccessControlClient
2835           .getUserPermissions(TEST_UTIL.getConnection(), tname.getNameAsString());
2836       assertEquals(2, userPermissions.size());
2837 
2838       AccessControlClient.revoke(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
2839         null, null, Action.WRITE);
2840 
2841       userPermissions = AccessControlClient.getUserPermissions(TEST_UTIL.getConnection(),
2842         tname.getNameAsString());
2843       assertEquals(2, userPermissions.size());
2844 
2845       Permission.Action[] expectedAction = { Action.READ };
2846       boolean userFound = false;
2847       for (UserPermission p : userPermissions) {
2848         if (testUserPerms.getShortName().equals(Bytes.toString(p.getUser()))) {
2849           assertArrayEquals(expectedAction, p.getActions());
2850           userFound = true;
2851           break;
2852         }
2853       }
2854       assertTrue(userFound);
2855     } finally {
2856       TEST_UTIL.deleteTable(tname);
2857     }
2858   }
2859 }