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