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