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