001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.access;
019
020import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
021import static org.junit.Assert.assertArrayEquals;
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertFalse;
024import static org.junit.Assert.assertNotNull;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.io.IOException;
029import java.security.PrivilegedAction;
030import java.util.ArrayList;
031import java.util.Arrays;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037import org.apache.hadoop.conf.Configuration;
038import org.apache.hadoop.fs.CommonConfigurationKeys;
039import org.apache.hadoop.fs.FileStatus;
040import org.apache.hadoop.fs.FileSystem;
041import org.apache.hadoop.fs.Path;
042import org.apache.hadoop.fs.permission.FsPermission;
043import org.apache.hadoop.hbase.Coprocessor;
044import org.apache.hadoop.hbase.CoprocessorEnvironment;
045import org.apache.hadoop.hbase.HBaseClassTestRule;
046import org.apache.hadoop.hbase.HBaseIOException;
047import org.apache.hadoop.hbase.HBaseTestingUtil;
048import org.apache.hadoop.hbase.HConstants;
049import org.apache.hadoop.hbase.HRegionLocation;
050import org.apache.hadoop.hbase.KeyValue;
051import org.apache.hadoop.hbase.NamespaceDescriptor;
052import org.apache.hadoop.hbase.ServerName;
053import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
054import org.apache.hadoop.hbase.TableName;
055import org.apache.hadoop.hbase.TableNotFoundException;
056import org.apache.hadoop.hbase.client.Admin;
057import org.apache.hadoop.hbase.client.Append;
058import org.apache.hadoop.hbase.client.BalanceRequest;
059import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
060import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
061import org.apache.hadoop.hbase.client.Connection;
062import org.apache.hadoop.hbase.client.ConnectionFactory;
063import org.apache.hadoop.hbase.client.Delete;
064import org.apache.hadoop.hbase.client.Get;
065import org.apache.hadoop.hbase.client.Hbck;
066import org.apache.hadoop.hbase.client.Increment;
067import org.apache.hadoop.hbase.client.MasterSwitchType;
068import org.apache.hadoop.hbase.client.Put;
069import org.apache.hadoop.hbase.client.RegionInfo;
070import org.apache.hadoop.hbase.client.RegionInfoBuilder;
071import org.apache.hadoop.hbase.client.RegionLocator;
072import org.apache.hadoop.hbase.client.Result;
073import org.apache.hadoop.hbase.client.ResultScanner;
074import org.apache.hadoop.hbase.client.Scan;
075import org.apache.hadoop.hbase.client.SnapshotDescription;
076import org.apache.hadoop.hbase.client.Table;
077import org.apache.hadoop.hbase.client.TableDescriptor;
078import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
079import org.apache.hadoop.hbase.client.TableState;
080import org.apache.hadoop.hbase.client.security.SecurityCapability;
081import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
082import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
083import org.apache.hadoop.hbase.coprocessor.ObserverContextImpl;
084import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
085import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
086import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
087import org.apache.hadoop.hbase.exceptions.HBaseException;
088import org.apache.hadoop.hbase.io.hfile.CacheConfig;
089import org.apache.hadoop.hbase.io.hfile.HFile;
090import org.apache.hadoop.hbase.io.hfile.HFileContext;
091import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
092import org.apache.hadoop.hbase.master.HMaster;
093import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
094import org.apache.hadoop.hbase.master.RegionState;
095import org.apache.hadoop.hbase.master.locking.LockProcedure;
096import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
097import org.apache.hadoop.hbase.master.procedure.TableProcedureInterface;
098import org.apache.hadoop.hbase.procedure2.LockType;
099import org.apache.hadoop.hbase.procedure2.Procedure;
100import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
101import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
102import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
103import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker;
104import org.apache.hadoop.hbase.regionserver.HRegion;
105import org.apache.hadoop.hbase.regionserver.HRegionServer;
106import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
107import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
108import org.apache.hadoop.hbase.regionserver.ScanType;
109import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
110import org.apache.hadoop.hbase.replication.SyncReplicationState;
111import org.apache.hadoop.hbase.security.Superusers;
112import org.apache.hadoop.hbase.security.User;
113import org.apache.hadoop.hbase.security.access.Permission.Action;
114import org.apache.hadoop.hbase.testclassification.LargeTests;
115import org.apache.hadoop.hbase.testclassification.SecurityTests;
116import org.apache.hadoop.hbase.tool.BulkLoadHFiles;
117import org.apache.hadoop.hbase.util.Bytes;
118import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
119import org.apache.hadoop.hbase.util.JVMClusterUtil;
120import org.apache.hadoop.hbase.util.Threads;
121import org.apache.hadoop.security.GroupMappingServiceProvider;
122import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
123import org.apache.hadoop.security.UserGroupInformation;
124import org.junit.AfterClass;
125import org.junit.BeforeClass;
126import org.junit.ClassRule;
127import org.junit.Rule;
128import org.junit.Test;
129import org.junit.experimental.categories.Category;
130import org.junit.rules.TestName;
131import org.slf4j.Logger;
132import org.slf4j.LoggerFactory;
133
134import org.apache.hbase.thirdparty.com.google.protobuf.BlockingRpcChannel;
135import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
136import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
137import org.apache.hbase.thirdparty.com.google.protobuf.Service;
138import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
139
140import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.CountRequest;
141import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.CountResponse;
142import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.HelloRequest;
143import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.HelloResponse;
144import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.IncrementCountRequest;
145import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.IncrementCountResponse;
146import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.NoopRequest;
147import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.NoopResponse;
148import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.PingRequest;
149import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.PingResponse;
150import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.PingService;
151import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestProcedureProtos;
152import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
153import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
154import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.AccessControlService;
155import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
156import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos.ProcedureState;
157
158/**
159 * Performs authorization checks for common operations, according to different levels of authorized
160 * users.
161 */
162@Category({ SecurityTests.class, LargeTests.class })
163public class TestAccessController extends SecureTestUtil {
164
165  @ClassRule
166  public static final HBaseClassTestRule CLASS_RULE =
167    HBaseClassTestRule.forClass(TestAccessController.class);
168
169  private static final FsPermission FS_PERMISSION_ALL = FsPermission.valueOf("-rwxrwxrwx");
170  private static final Logger LOG = LoggerFactory.getLogger(TestAccessController.class);
171  private static TableName TEST_TABLE = TableName.valueOf("testtable1");
172  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
173  private static Configuration conf;
174
175  /**
176   * The systemUserConnection created here is tied to the system user. In case, you are planning to
177   * create AccessTestAction, DON'T use this systemUserConnection as the 'doAs' user gets eclipsed
178   * by the system user.
179   */
180  private static Connection systemUserConnection;
181
182  // user with all permissions
183  private static User SUPERUSER;
184  // user granted with all global permission
185  private static User USER_ADMIN;
186  // user with rw permissions on column family.
187  private static User USER_RW;
188  // user with read-only permissions
189  private static User USER_RO;
190  // user is table owner. will have all permissions on table
191  private static User USER_OWNER;
192  // user with create table permissions alone
193  private static User USER_CREATE;
194  // user with no permissions
195  private static User USER_NONE;
196  // user with admin rights on the column family
197  private static User USER_ADMIN_CF;
198
199  private static final String GROUP_ADMIN = "group_admin";
200  private static final String GROUP_CREATE = "group_create";
201  private static final String GROUP_READ = "group_read";
202  private static final String GROUP_WRITE = "group_write";
203
204  private static User USER_GROUP_ADMIN;
205  private static User USER_GROUP_CREATE;
206  private static User USER_GROUP_READ;
207  private static User USER_GROUP_WRITE;
208
209  // TODO: convert this test to cover the full matrix in
210  // https://hbase.apache.org/book/appendix_acl_matrix.html
211  // creating all Scope x Permission combinations
212
213  private static TableName TEST_TABLE2 = TableName.valueOf("testtable2");
214  private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
215  private static byte[] TEST_QUALIFIER = Bytes.toBytes("q1");
216  private static byte[] TEST_ROW = Bytes.toBytes("r1");
217
218  private static MasterCoprocessorEnvironment CP_ENV;
219  private static AccessController ACCESS_CONTROLLER;
220  private static RegionServerCoprocessorEnvironment RSCP_ENV;
221  private static RegionCoprocessorEnvironment RCP_ENV;
222
223  @Rule
224  public TestName name = new TestName();
225
226  @BeforeClass
227  public static void setupBeforeClass() throws Exception {
228    // setup configuration
229    conf = TEST_UTIL.getConfiguration();
230    // Up the handlers; this test needs more than usual.
231    conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
232
233    conf.set(CommonConfigurationKeys.HADOOP_SECURITY_GROUP_MAPPING,
234      MyShellBasedUnixGroupsMapping.class.getName());
235    UserGroupInformation.setConfiguration(conf);
236
237    // Enable security
238    enableSecurity(conf);
239    // In this particular test case, we can't use SecureBulkLoadEndpoint because its doAs will fail
240    // to move a file for a random user
241    conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
242    // Verify enableSecurity sets up what we require
243    verifyConfiguration(conf);
244
245    // Enable EXEC permission checking
246    conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true);
247
248    TEST_UTIL.startMiniCluster();
249    MasterCoprocessorHost masterCpHost =
250      TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
251    masterCpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
252    ACCESS_CONTROLLER = masterCpHost.findCoprocessor(AccessController.class);
253    CP_ENV =
254      masterCpHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
255    RegionServerCoprocessorHost rsCpHost =
256      TEST_UTIL.getMiniHBaseCluster().getRegionServer(0).getRegionServerCoprocessorHost();
257    RSCP_ENV = rsCpHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
258
259    // Wait for the ACL table to become available
260    TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME);
261
262    // create a set of test users
263    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
264    USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
265    USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
266    USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
267    USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
268    USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
269    USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
270    USER_ADMIN_CF = User.createUserForTesting(conf, "col_family_admin", new String[0]);
271
272    USER_GROUP_ADMIN =
273      User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN });
274    USER_GROUP_CREATE =
275      User.createUserForTesting(conf, "user_group_create", new String[] { GROUP_CREATE });
276    USER_GROUP_READ =
277      User.createUserForTesting(conf, "user_group_read", new String[] { GROUP_READ });
278    USER_GROUP_WRITE =
279      User.createUserForTesting(conf, "user_group_write", new String[] { GROUP_WRITE });
280
281    // Grant table creation permission to USER_OWNER
282    grantGlobal(TEST_UTIL, USER_OWNER.getShortName(), Action.CREATE);
283
284    systemUserConnection = TEST_UTIL.getConnection();
285    setUpTableAndUserPermissions();
286  }
287
288  @AfterClass
289  public static void tearDownAfterClass() throws Exception {
290    cleanUp();
291    TEST_UTIL.shutdownMiniCluster();
292  }
293
294  private static void setUpTableAndUserPermissions() throws Exception {
295    TableDescriptor tableDescriptor =
296      TableDescriptorBuilder.newBuilder(TEST_TABLE)
297        .setColumnFamily(
298          ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY).setMaxVersions(100).build())
299        .build();
300    createTable(TEST_UTIL, USER_OWNER, tableDescriptor, new byte[][] { Bytes.toBytes("s") });
301
302    HRegion region = TEST_UTIL.getHBaseCluster().getRegions(TEST_TABLE).get(0);
303    RegionCoprocessorHost rcpHost = region.getCoprocessorHost();
304    RCP_ENV = rcpHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
305
306    // Set up initial grants
307
308    grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(), Permission.Action.ADMIN,
309      Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE);
310
311    grantOnTable(TEST_UTIL, USER_RW.getShortName(), TEST_TABLE, TEST_FAMILY, null,
312      Permission.Action.READ, Permission.Action.WRITE);
313
314    // USER_CREATE is USER_RW plus CREATE permissions
315    grantOnTable(TEST_UTIL, USER_CREATE.getShortName(), TEST_TABLE, null, null,
316      Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE);
317
318    grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
319      Permission.Action.READ);
320
321    grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(), TEST_TABLE, TEST_FAMILY, null,
322      Permission.Action.ADMIN, Permission.Action.CREATE);
323
324    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN);
325    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_CREATE), Permission.Action.CREATE);
326    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ);
327    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE);
328
329    assertEquals(5, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size());
330    int size = 0;
331    try {
332      size =
333        AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()).size();
334    } catch (Throwable e) {
335      LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
336      fail("error during call of AccessControlClient.getUserPermissions.");
337    }
338    assertEquals(5, size);
339  }
340
341  private static void cleanUp() throws Exception {
342    // Clean the _acl_ table
343    try {
344      deleteTable(TEST_UTIL, TEST_TABLE);
345    } catch (TableNotFoundException ex) {
346      // Test deleted the table, no problem
347      LOG.info("Test deleted table " + TEST_TABLE);
348    }
349    // Verify all table/namespace permissions are erased
350    assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size());
351    assertEquals(0,
352      PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size());
353  }
354
355  @Test
356  public void testUnauthorizedShutdown() throws Exception {
357    AccessTestAction action = new AccessTestAction() {
358      @Override
359      public Object run() throws Exception {
360        HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
361        master.shutdown();
362        return null;
363      }
364    };
365    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
366      USER_GROUP_WRITE, USER_GROUP_CREATE);
367  }
368
369  @Test
370  public void testUnauthorizedStopMaster() throws Exception {
371    AccessTestAction action = new AccessTestAction() {
372      @Override
373      public Object run() throws Exception {
374        HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
375        master.stopMaster();
376        return null;
377      }
378    };
379
380    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
381      USER_GROUP_WRITE, USER_GROUP_CREATE);
382  }
383
384  @Test
385  public void testUnauthorizedSetTableStateInMeta() throws Exception {
386    AccessTestAction action = () -> {
387      try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
388        Hbck hbck = conn.getHbck()) {
389        hbck.setTableStateInMeta(new TableState(TEST_TABLE, TableState.State.DISABLED));
390      }
391      return null;
392    };
393
394    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
395      USER_GROUP_WRITE, USER_GROUP_CREATE);
396  }
397
398  @Test
399  public void testUnauthorizedSetRegionStateInMeta() throws Exception {
400    Admin admin = TEST_UTIL.getAdmin();
401    final List<RegionInfo> regions = admin.getRegions(TEST_TABLE);
402    RegionInfo closeRegion = regions.get(0);
403    Map<String, RegionState.State> newStates = new HashMap<>();
404    newStates.put(closeRegion.getEncodedName(), RegionState.State.CLOSED);
405    AccessTestAction action = () -> {
406      try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
407        Hbck hbck = conn.getHbck()) {
408        hbck.setRegionStateInMeta(newStates);
409      }
410      return null;
411    };
412
413    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
414      USER_GROUP_WRITE, USER_GROUP_CREATE);
415  }
416
417  @Test
418  public void testUnauthorizedFixMeta() throws Exception {
419    AccessTestAction action = () -> {
420      try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
421        Hbck hbck = conn.getHbck()) {
422        hbck.fixMeta();
423      }
424      return null;
425    };
426
427    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
428      USER_GROUP_WRITE, USER_GROUP_CREATE);
429  }
430
431  @Test
432  public void testSecurityCapabilities() throws Exception {
433    List<SecurityCapability> capabilities =
434      TEST_UTIL.getConnection().getAdmin().getSecurityCapabilities();
435    assertTrue("AUTHORIZATION capability is missing",
436      capabilities.contains(SecurityCapability.AUTHORIZATION));
437    assertTrue("CELL_AUTHORIZATION capability is missing",
438      capabilities.contains(SecurityCapability.CELL_AUTHORIZATION));
439  }
440
441  @Test
442  public void testTableCreate() throws Exception {
443    AccessTestAction createTable = new AccessTestAction() {
444      @Override
445      public Object run() throws Exception {
446        TableDescriptor tableDescriptor =
447          TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName()))
448            .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
449        ACCESS_CONTROLLER.preCreateTable(ObserverContextImpl.createAndPrepare(CP_ENV),
450          tableDescriptor, null);
451        return null;
452      }
453    };
454
455    // verify that superuser can create tables
456    verifyAllowed(createTable, SUPERUSER, USER_ADMIN, USER_GROUP_CREATE, USER_GROUP_ADMIN);
457
458    // all others should be denied
459    verifyDenied(createTable, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
460      USER_GROUP_WRITE);
461  }
462
463  @Test
464  public void testTableModify() throws Exception {
465    AccessTestAction modifyTable = new AccessTestAction() {
466      @Override
467      public Object run() throws Exception {
468        TableDescriptorBuilder tableDescriptorBuilder =
469          TableDescriptorBuilder.newBuilder(TEST_TABLE);
470        ColumnFamilyDescriptor columnFamilyDescriptor =
471          ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY).build();
472        tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor);
473        columnFamilyDescriptor = ColumnFamilyDescriptorBuilder
474          .newBuilder(Bytes.toBytes("fam_" + User.getCurrent().getShortName())).build();
475        tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor);
476        ACCESS_CONTROLLER.preModifyTable(ObserverContextImpl.createAndPrepare(CP_ENV), TEST_TABLE,
477          null, // not needed by AccessController
478          tableDescriptorBuilder.build());
479        return null;
480      }
481    };
482
483    verifyAllowed(modifyTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
484      USER_GROUP_ADMIN);
485    verifyDenied(modifyTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
486  }
487
488  @Test
489  public void testTableDelete() throws Exception {
490    AccessTestAction deleteTable = new AccessTestAction() {
491      @Override
492      public Object run() throws Exception {
493        ACCESS_CONTROLLER.preDeleteTable(ObserverContextImpl.createAndPrepare(CP_ENV), TEST_TABLE);
494        return null;
495      }
496    };
497
498    verifyAllowed(deleteTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
499      USER_GROUP_ADMIN);
500    verifyDenied(deleteTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
501  }
502
503  @Test
504  public void testTableTruncate() throws Exception {
505    AccessTestAction truncateTable = new AccessTestAction() {
506      @Override
507      public Object run() throws Exception {
508        ACCESS_CONTROLLER.preTruncateTable(ObserverContextImpl.createAndPrepare(CP_ENV),
509          TEST_TABLE);
510        return null;
511      }
512    };
513
514    verifyAllowed(truncateTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
515      USER_GROUP_ADMIN);
516    verifyDenied(truncateTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
517  }
518
519  @Test
520  public void testTableDisable() throws Exception {
521    AccessTestAction disableTable = new AccessTestAction() {
522      @Override
523      public Object run() throws Exception {
524        ACCESS_CONTROLLER.preDisableTable(ObserverContextImpl.createAndPrepare(CP_ENV), TEST_TABLE);
525        return null;
526      }
527    };
528
529    AccessTestAction disableAclTable = new AccessTestAction() {
530      @Override
531      public Object run() throws Exception {
532        ACCESS_CONTROLLER.preDisableTable(ObserverContextImpl.createAndPrepare(CP_ENV),
533          PermissionStorage.ACL_TABLE_NAME);
534        return null;
535      }
536    };
537
538    verifyAllowed(disableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
539      USER_GROUP_ADMIN);
540    verifyDenied(disableTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
541
542    // No user should be allowed to disable _acl_ table
543    verifyDenied(disableAclTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
544      USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_WRITE);
545  }
546
547  @Test
548  public void testTableEnable() throws Exception {
549    AccessTestAction enableTable = new AccessTestAction() {
550      @Override
551      public Object run() throws Exception {
552        ACCESS_CONTROLLER.preEnableTable(ObserverContextImpl.createAndPrepare(CP_ENV), TEST_TABLE);
553        return null;
554      }
555    };
556
557    verifyAllowed(enableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_GROUP_CREATE,
558      USER_GROUP_ADMIN);
559    verifyDenied(enableTable, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
560  }
561
562  public static class TestTableDDLProcedure extends Procedure<MasterProcedureEnv>
563    implements TableProcedureInterface {
564    private TableName tableName;
565
566    public TestTableDDLProcedure() {
567    }
568
569    public TestTableDDLProcedure(final MasterProcedureEnv env, final TableName tableName)
570      throws IOException {
571      this.tableName = tableName;
572      this.setTimeout(180000); // Timeout in 3 minutes
573      this.setOwner(env.getRequestUser());
574    }
575
576    @Override
577    public TableName getTableName() {
578      return tableName;
579    }
580
581    @Override
582    public TableOperationType getTableOperationType() {
583      return TableOperationType.EDIT;
584    }
585
586    @Override
587    protected boolean abort(MasterProcedureEnv env) {
588      return true;
589    }
590
591    @Override
592    protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
593      TestProcedureProtos.TestTableDDLStateData.Builder testTableDDLMsg =
594        TestProcedureProtos.TestTableDDLStateData.newBuilder()
595          .setTableName(tableName.getNameAsString());
596      serializer.serialize(testTableDDLMsg.build());
597    }
598
599    @Override
600    protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
601      TestProcedureProtos.TestTableDDLStateData testTableDDLMsg =
602        serializer.deserialize(TestProcedureProtos.TestTableDDLStateData.class);
603      tableName = TableName.valueOf(testTableDDLMsg.getTableName());
604    }
605
606    @Override
607    protected Procedure[] execute(MasterProcedureEnv env)
608      throws ProcedureYieldException, InterruptedException {
609      // Not letting the procedure to complete until timed out
610      setState(ProcedureState.WAITING_TIMEOUT);
611      return null;
612    }
613
614    @Override
615    protected void rollback(MasterProcedureEnv env) throws IOException, InterruptedException {
616    }
617  }
618
619  @Test
620  public void testAbortProcedure() throws Exception {
621    long procId = 1;
622    AccessTestAction abortProcedureAction = new AccessTestAction() {
623      @Override
624      public Object run() throws Exception {
625        ACCESS_CONTROLLER.preAbortProcedure(ObserverContextImpl.createAndPrepare(CP_ENV), procId);
626        return null;
627      }
628    };
629
630    verifyAllowed(abortProcedureAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
631  }
632
633  @Test
634  public void testGetProcedures() throws Exception {
635    final TableName tableName = TableName.valueOf(name.getMethodName());
636    final ProcedureExecutor<MasterProcedureEnv> procExec =
637      TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
638    Procedure proc = new TestTableDDLProcedure(procExec.getEnvironment(), tableName);
639    proc.setOwner(USER_OWNER);
640    procExec.submitProcedure(proc);
641    final List<Procedure<MasterProcedureEnv>> procList = procExec.getProcedures();
642
643    AccessTestAction getProceduresAction = new AccessTestAction() {
644      @Override
645      public Object run() throws Exception {
646        ACCESS_CONTROLLER.postGetProcedures(ObserverContextImpl.createAndPrepare(CP_ENV));
647        return null;
648      }
649    };
650
651    verifyAllowed(getProceduresAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
652    verifyAllowed(getProceduresAction, USER_OWNER);
653    verifyIfNull(getProceduresAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
654      USER_GROUP_WRITE);
655  }
656
657  @Test
658  public void testGetLocks() throws Exception {
659    AccessTestAction action = new AccessTestAction() {
660      @Override
661      public Object run() throws Exception {
662        ACCESS_CONTROLLER.preGetLocks(ObserverContextImpl.createAndPrepare(CP_ENV));
663        return null;
664      }
665    };
666
667    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
668    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
669      USER_GROUP_WRITE, USER_GROUP_CREATE);
670  }
671
672  @Test
673  public void testMove() throws Exception {
674    List<HRegionLocation> regions;
675    try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
676      regions = locator.getAllRegionLocations();
677    }
678    HRegionLocation location = regions.get(0);
679    final RegionInfo hri = location.getRegion();
680    final ServerName server = location.getServerName();
681    AccessTestAction action = new AccessTestAction() {
682      @Override
683      public Object run() throws Exception {
684        ACCESS_CONTROLLER.preMove(ObserverContextImpl.createAndPrepare(CP_ENV), hri, server,
685          server);
686        return null;
687      }
688    };
689
690    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
691    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
692      USER_GROUP_WRITE, USER_GROUP_CREATE);
693  }
694
695  @Test
696  public void testAssign() throws Exception {
697    List<HRegionLocation> regions;
698    try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
699      regions = locator.getAllRegionLocations();
700    }
701    HRegionLocation location = regions.get(0);
702    final RegionInfo hri = location.getRegion();
703    AccessTestAction action = new AccessTestAction() {
704      @Override
705      public Object run() throws Exception {
706        ACCESS_CONTROLLER.preAssign(ObserverContextImpl.createAndPrepare(CP_ENV), hri);
707        return null;
708      }
709    };
710
711    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
712    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
713      USER_GROUP_WRITE, USER_GROUP_CREATE);
714  }
715
716  @Test
717  public void testUnassign() throws Exception {
718    List<HRegionLocation> regions;
719    try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
720      regions = locator.getAllRegionLocations();
721    }
722    HRegionLocation location = regions.get(0);
723    final RegionInfo hri = location.getRegion();
724    AccessTestAction action = new AccessTestAction() {
725      @Override
726      public Object run() throws Exception {
727        ACCESS_CONTROLLER.preUnassign(ObserverContextImpl.createAndPrepare(CP_ENV), hri);
728        return null;
729      }
730    };
731
732    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
733    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
734      USER_GROUP_WRITE, USER_GROUP_CREATE);
735  }
736
737  @Test
738  public void testRegionOffline() throws Exception {
739    List<HRegionLocation> regions;
740    try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE)) {
741      regions = locator.getAllRegionLocations();
742    }
743    HRegionLocation location = regions.get(0);
744    final RegionInfo hri = location.getRegion();
745    AccessTestAction action = new AccessTestAction() {
746      @Override
747      public Object run() throws Exception {
748        ACCESS_CONTROLLER.preRegionOffline(ObserverContextImpl.createAndPrepare(CP_ENV), hri);
749        return null;
750      }
751    };
752
753    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
754    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
755      USER_GROUP_WRITE, USER_GROUP_CREATE);
756  }
757
758  @Test
759  public void testSetSplitOrMergeEnabled() throws Exception {
760    AccessTestAction action = new AccessTestAction() {
761      @Override
762      public Object run() throws Exception {
763        ACCESS_CONTROLLER.preSetSplitOrMergeEnabled(ObserverContextImpl.createAndPrepare(CP_ENV),
764          true, MasterSwitchType.MERGE);
765        return null;
766      }
767    };
768
769    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
770    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
771      USER_GROUP_WRITE, USER_GROUP_CREATE);
772  }
773
774  @Test
775  public void testBalance() throws Exception {
776    AccessTestAction action = new AccessTestAction() {
777      @Override
778      public Object run() throws Exception {
779        ACCESS_CONTROLLER.preBalance(ObserverContextImpl.createAndPrepare(CP_ENV),
780          BalanceRequest.defaultInstance());
781        return null;
782      }
783    };
784
785    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
786    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
787      USER_GROUP_WRITE, USER_GROUP_CREATE);
788  }
789
790  @Test
791  public void testBalanceSwitch() throws Exception {
792    AccessTestAction action = new AccessTestAction() {
793      @Override
794      public Object run() throws Exception {
795        ACCESS_CONTROLLER.preBalanceSwitch(ObserverContextImpl.createAndPrepare(CP_ENV), true);
796        return null;
797      }
798    };
799
800    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
801    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
802      USER_GROUP_WRITE, USER_GROUP_CREATE);
803  }
804
805  @Test
806  public void testShutdown() throws Exception {
807    AccessTestAction action = new AccessTestAction() {
808      @Override
809      public Object run() throws Exception {
810        ACCESS_CONTROLLER.preShutdown(ObserverContextImpl.createAndPrepare(CP_ENV));
811        return null;
812      }
813    };
814
815    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
816    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
817      USER_GROUP_WRITE, USER_GROUP_CREATE);
818  }
819
820  @Test
821  public void testStopMaster() throws Exception {
822    AccessTestAction action = new AccessTestAction() {
823      @Override
824      public Object run() throws Exception {
825        ACCESS_CONTROLLER.preStopMaster(ObserverContextImpl.createAndPrepare(CP_ENV));
826        return null;
827      }
828    };
829
830    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
831    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
832      USER_GROUP_WRITE, USER_GROUP_CREATE);
833  }
834
835  private void verifyWrite(AccessTestAction action) throws Exception {
836    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
837      USER_GROUP_WRITE);
838    verifyDenied(action, USER_NONE, USER_RO, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_CREATE);
839  }
840
841  @Test
842  public void testSplitWithSplitRow() throws Exception {
843    final TableName tableName = TableName.valueOf(name.getMethodName());
844    createTestTable(tableName);
845    AccessTestAction action = new AccessTestAction() {
846      @Override
847      public Object run() throws Exception {
848        ACCESS_CONTROLLER.preSplitRegion(ObserverContextImpl.createAndPrepare(CP_ENV), tableName,
849          TEST_ROW);
850        return null;
851      }
852    };
853
854    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
855    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
856      USER_GROUP_WRITE, USER_GROUP_CREATE);
857  }
858
859  @Test
860  public void testFlush() throws Exception {
861    AccessTestAction action = new AccessTestAction() {
862      @Override
863      public Object run() throws Exception {
864        ACCESS_CONTROLLER.preFlush(ObserverContextImpl.createAndPrepare(RCP_ENV),
865          FlushLifeCycleTracker.DUMMY);
866        return null;
867      }
868    };
869
870    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_GROUP_CREATE,
871      USER_GROUP_ADMIN);
872    verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
873  }
874
875  @Test
876  public void testCompact() throws Exception {
877    AccessTestAction action = new AccessTestAction() {
878      @Override
879      public Object run() throws Exception {
880        ACCESS_CONTROLLER.preCompact(ObserverContextImpl.createAndPrepare(RCP_ENV), null, null,
881          ScanType.COMPACT_RETAIN_DELETES, null, null);
882        return null;
883      }
884    };
885
886    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_GROUP_CREATE,
887      USER_GROUP_ADMIN);
888    verifyDenied(action, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
889  }
890
891  private void verifyRead(AccessTestAction action) throws Exception {
892    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
893      USER_GROUP_READ);
894    verifyDenied(action, USER_NONE, USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_WRITE);
895  }
896
897  private void verifyReadWrite(AccessTestAction action) throws Exception {
898    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
899    verifyDenied(action, USER_NONE, USER_RO, USER_GROUP_ADMIN, USER_GROUP_CREATE, USER_GROUP_READ,
900      USER_GROUP_WRITE);
901  }
902
903  @Test
904  public void testRead() throws Exception {
905    // get action
906    AccessTestAction getAction = new AccessTestAction() {
907      @Override
908      public Object run() throws Exception {
909        Get g = new Get(TEST_ROW);
910        g.addFamily(TEST_FAMILY);
911        try (Connection conn = ConnectionFactory.createConnection(conf);
912          Table t = conn.getTable(TEST_TABLE)) {
913          t.get(g);
914        }
915        return null;
916      }
917    };
918    verifyRead(getAction);
919
920    // action for scanning
921    AccessTestAction scanAction = new AccessTestAction() {
922      @Override
923      public Object run() throws Exception {
924        Scan s = new Scan();
925        s.addFamily(TEST_FAMILY);
926        try (Connection conn = ConnectionFactory.createConnection(conf);
927          Table table = conn.getTable(TEST_TABLE)) {
928          ResultScanner scanner = table.getScanner(s);
929          try {
930            for (Result r = scanner.next(); r != null; r = scanner.next()) {
931              // do nothing
932            }
933          } finally {
934            scanner.close();
935          }
936        }
937        return null;
938      }
939    };
940    verifyRead(scanAction);
941  }
942
943  @Test
944  // test put, delete, increment
945  public void testWrite() throws Exception {
946    // put action
947    AccessTestAction putAction = new AccessTestAction() {
948      @Override
949      public Object run() throws Exception {
950        Put p = new Put(TEST_ROW);
951        p.addColumn(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
952        try (Connection conn = ConnectionFactory.createConnection(conf);
953          Table t = conn.getTable(TEST_TABLE)) {
954          t.put(p);
955        }
956        return null;
957      }
958    };
959    verifyWrite(putAction);
960
961    // delete action
962    AccessTestAction deleteAction = new AccessTestAction() {
963      @Override
964      public Object run() throws Exception {
965        Delete d = new Delete(TEST_ROW);
966        d.addFamily(TEST_FAMILY);
967        try (Connection conn = ConnectionFactory.createConnection(conf);
968          Table t = conn.getTable(TEST_TABLE)) {
969          t.delete(d);
970        }
971        return null;
972      }
973    };
974    verifyWrite(deleteAction);
975
976    // increment action
977    AccessTestAction incrementAction = new AccessTestAction() {
978      @Override
979      public Object run() throws Exception {
980        Increment inc = new Increment(TEST_ROW);
981        inc.addColumn(TEST_FAMILY, TEST_QUALIFIER, 1);
982        try (Connection conn = ConnectionFactory.createConnection(conf);
983          Table t = conn.getTable(TEST_TABLE)) {
984          t.increment(inc);
985        }
986        return null;
987      }
988    };
989    verifyWrite(incrementAction);
990  }
991
992  @Test
993  public void testReadWrite() throws Exception {
994    // action for checkAndDelete
995    AccessTestAction checkAndDeleteAction = new AccessTestAction() {
996      @Override
997      public Object run() throws Exception {
998        Delete d = new Delete(TEST_ROW);
999        d.addFamily(TEST_FAMILY);
1000        try (Connection conn = ConnectionFactory.createConnection(conf);
1001          Table t = conn.getTable(TEST_TABLE)) {
1002          t.checkAndMutate(TEST_ROW, TEST_FAMILY).qualifier(TEST_QUALIFIER)
1003            .ifEquals(Bytes.toBytes("test_value")).thenDelete(d);
1004        }
1005        return null;
1006      }
1007    };
1008    verifyReadWrite(checkAndDeleteAction);
1009
1010    // action for checkAndPut()
1011    AccessTestAction checkAndPut = new AccessTestAction() {
1012      @Override
1013      public Object run() throws Exception {
1014        Put p = new Put(TEST_ROW);
1015        p.addColumn(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
1016        try (Connection conn = ConnectionFactory.createConnection(conf);
1017          Table t = conn.getTable(TEST_TABLE)) {
1018          t.checkAndMutate(TEST_ROW, TEST_FAMILY).qualifier(TEST_QUALIFIER)
1019            .ifEquals(Bytes.toBytes("test_value")).thenPut(p);
1020        }
1021        return null;
1022      }
1023    };
1024    verifyReadWrite(checkAndPut);
1025  }
1026
1027  @Test
1028  public void testBulkLoad() throws Exception {
1029    try {
1030      FileSystem fs = TEST_UTIL.getTestFileSystem();
1031      final Path dir = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoad");
1032      fs.mkdirs(dir);
1033      // need to make it globally writable
1034      // so users creating HFiles have write permissions
1035      fs.setPermission(dir, FS_PERMISSION_ALL);
1036
1037      AccessTestAction bulkLoadAction = new AccessTestAction() {
1038        @Override
1039        public Object run() throws Exception {
1040          int numRows = 3;
1041
1042          // Making the assumption that the test table won't split between the range
1043          byte[][][] hfileRanges = { { { (byte) 0 }, { (byte) 9 } } };
1044
1045          Path bulkLoadBasePath = new Path(dir, new Path(User.getCurrent().getName()));
1046          new BulkLoadHelper(bulkLoadBasePath)
1047            .initHFileData(TEST_FAMILY, TEST_QUALIFIER, hfileRanges, numRows, FS_PERMISSION_ALL)
1048            .bulkLoadHFile(TEST_TABLE);
1049          return null;
1050        }
1051      };
1052
1053      // User performing bulk loads must have privilege to read table metadata
1054      // (ADMIN or CREATE)
1055      verifyAllowed(bulkLoadAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
1056        USER_GROUP_CREATE, USER_GROUP_ADMIN);
1057      verifyDenied(bulkLoadAction, USER_RW, USER_NONE, USER_RO, USER_GROUP_READ, USER_GROUP_WRITE);
1058    } finally {
1059      // Reinit after the bulk upload
1060      TEST_UTIL.getAdmin().disableTable(TEST_TABLE);
1061      TEST_UTIL.getAdmin().enableTable(TEST_TABLE);
1062    }
1063  }
1064
1065  private class BulkLoadAccessTestAction implements AccessTestAction {
1066    private FsPermission filePermission;
1067    private Path testDataDir;
1068
1069    public BulkLoadAccessTestAction(FsPermission perm, Path testDataDir) {
1070      this.filePermission = perm;
1071      this.testDataDir = testDataDir;
1072    }
1073
1074    @Override
1075    public Object run() throws Exception {
1076      FileSystem fs = TEST_UTIL.getTestFileSystem();
1077      fs.mkdirs(testDataDir);
1078      fs.setPermission(testDataDir, FS_PERMISSION_ALL);
1079      // Making the assumption that the test table won't split between the range
1080      byte[][][] hfileRanges = { { { (byte) 0 }, { (byte) 9 } } };
1081      Path bulkLoadBasePath = new Path(testDataDir, new Path(User.getCurrent().getName()));
1082      new BulkLoadHelper(bulkLoadBasePath)
1083        .initHFileData(TEST_FAMILY, TEST_QUALIFIER, hfileRanges, 3, filePermission)
1084        .bulkLoadHFile(TEST_TABLE);
1085      return null;
1086    }
1087  }
1088
1089  @Test
1090  public void testBulkLoadWithoutWritePermission() throws Exception {
1091    // Use the USER_CREATE to initialize the source directory.
1092    Path testDataDir0 = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoadWithoutWritePermission0");
1093    Path testDataDir1 = TEST_UTIL.getDataTestDirOnTestFS("testBulkLoadWithoutWritePermission1");
1094    AccessTestAction bulkLoadAction1 =
1095      new BulkLoadAccessTestAction(FsPermission.valueOf("-r-xr-xr-x"), testDataDir0);
1096    AccessTestAction bulkLoadAction2 =
1097      new BulkLoadAccessTestAction(FS_PERMISSION_ALL, testDataDir1);
1098    // Test the incorrect case.
1099    BulkLoadHelper.setPermission(TEST_UTIL.getTestFileSystem(),
1100      TEST_UTIL.getTestFileSystem().getWorkingDirectory(), FS_PERMISSION_ALL);
1101    try {
1102      USER_CREATE.runAs(bulkLoadAction1);
1103      fail("Should fail because the hbase user has no write permission on hfiles.");
1104    } catch (IOException e) {
1105    }
1106    // Ensure the correct case.
1107    USER_CREATE.runAs(bulkLoadAction2);
1108  }
1109
1110  public static class BulkLoadHelper {
1111    private final FileSystem fs;
1112    private final Path loadPath;
1113    private final Configuration conf;
1114
1115    public BulkLoadHelper(Path loadPath) throws IOException {
1116      fs = TEST_UTIL.getTestFileSystem();
1117      conf = TEST_UTIL.getConfiguration();
1118      loadPath = loadPath.makeQualified(fs);
1119      this.loadPath = loadPath;
1120    }
1121
1122    private void createHFile(Path path, byte[] family, byte[] qualifier, byte[] startKey,
1123      byte[] endKey, int numRows) throws IOException {
1124      HFile.Writer writer = null;
1125      long now = EnvironmentEdgeManager.currentTime();
1126      try {
1127        HFileContext context = new HFileContextBuilder().build();
1128        writer = HFile.getWriterFactory(conf, new CacheConfig(conf)).withPath(fs, path)
1129          .withFileContext(context).create();
1130        // subtract 2 since numRows doesn't include boundary keys
1131        for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, true, numRows - 2)) {
1132          KeyValue kv = new KeyValue(key, family, qualifier, now, key);
1133          writer.append(kv);
1134        }
1135      } finally {
1136        if (writer != null) {
1137          writer.close();
1138        }
1139      }
1140    }
1141
1142    private BulkLoadHelper initHFileData(byte[] family, byte[] qualifier, byte[][][] hfileRanges,
1143      int numRowsPerRange, FsPermission filePermission) throws Exception {
1144      Path familyDir = new Path(loadPath, Bytes.toString(family));
1145      fs.mkdirs(familyDir);
1146      int hfileIdx = 0;
1147      List<Path> hfiles = new ArrayList<>();
1148      for (byte[][] range : hfileRanges) {
1149        byte[] from = range[0];
1150        byte[] to = range[1];
1151        Path hfile = new Path(familyDir, "hfile_" + (hfileIdx++));
1152        hfiles.add(hfile);
1153        createHFile(hfile, family, qualifier, from, to, numRowsPerRange);
1154      }
1155      // set global read so RegionServer can move it
1156      setPermission(fs, loadPath, FS_PERMISSION_ALL);
1157      // Ensure the file permission as requested.
1158      for (Path hfile : hfiles) {
1159        setPermission(fs, hfile, filePermission);
1160      }
1161      return this;
1162    }
1163
1164    private void bulkLoadHFile(TableName tableName) throws Exception {
1165      TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
1166      BulkLoadHFiles.create(conf).bulkLoad(tableName, loadPath);
1167    }
1168
1169    private static void setPermission(FileSystem fs, Path dir, FsPermission perm)
1170      throws IOException {
1171      if (!fs.getFileStatus(dir).isDirectory()) {
1172        fs.setPermission(dir, perm);
1173      } else {
1174        for (FileStatus el : fs.listStatus(dir)) {
1175          fs.setPermission(el.getPath(), perm);
1176          setPermission(fs, el.getPath(), perm);
1177        }
1178      }
1179    }
1180  }
1181
1182  @Test
1183  public void testAppend() throws Exception {
1184
1185    AccessTestAction appendAction = new AccessTestAction() {
1186      @Override
1187      public Object run() throws Exception {
1188        byte[] row = TEST_ROW;
1189        byte[] qualifier = TEST_QUALIFIER;
1190        Put put = new Put(row);
1191        put.addColumn(TEST_FAMILY, qualifier, Bytes.toBytes(1));
1192        Append append = new Append(row);
1193        append.addColumn(TEST_FAMILY, qualifier, Bytes.toBytes(2));
1194        try (Connection conn = ConnectionFactory.createConnection(conf);
1195          Table t = conn.getTable(TEST_TABLE)) {
1196          t.put(put);
1197          t.append(append);
1198        }
1199        return null;
1200      }
1201    };
1202
1203    verifyAllowed(appendAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
1204      USER_GROUP_WRITE);
1205    verifyDenied(appendAction, USER_RO, USER_NONE, USER_GROUP_CREATE, USER_GROUP_READ,
1206      USER_GROUP_ADMIN);
1207  }
1208
1209  @Test
1210  public void testGrantRevoke() throws Exception {
1211    AccessTestAction grantAction = new AccessTestAction() {
1212      @Override
1213      public Object run() throws Exception {
1214        try (Connection conn = ConnectionFactory.createConnection(conf)) {
1215          conn.getAdmin().grant(new UserPermission(USER_RO.getShortName(), Permission
1216            .newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withActions(Action.READ).build()),
1217            false);
1218        }
1219        return null;
1220      }
1221    };
1222
1223    AccessTestAction revokeAction = new AccessTestAction() {
1224      @Override
1225      public Object run() throws Exception {
1226        try (Connection conn = ConnectionFactory.createConnection(conf)) {
1227          conn.getAdmin().revoke(new UserPermission(USER_RO.getShortName(), Permission
1228            .newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withActions(Action.READ).build()));
1229        }
1230        return null;
1231      }
1232    };
1233
1234    AccessTestAction getTablePermissionsAction = new AccessTestAction() {
1235      @Override
1236      public Object run() throws Exception {
1237        try (Connection conn = ConnectionFactory.createConnection(conf)) {
1238          conn.getAdmin()
1239            .getUserPermissions(GetUserPermissionsRequest.newBuilder(TEST_TABLE).build());
1240        }
1241        return null;
1242      }
1243    };
1244
1245    AccessTestAction getGlobalPermissionsAction = new AccessTestAction() {
1246      @Override
1247      public Object run() throws Exception {
1248        try (Connection conn = ConnectionFactory.createConnection(conf)) {
1249          conn.getAdmin().getUserPermissions(GetUserPermissionsRequest.newBuilder().build());
1250        }
1251        return null;
1252      }
1253    };
1254
1255    AccessTestAction preGrantAction = new AccessTestAction() {
1256      @Override
1257      public Object run() throws Exception {
1258        ACCESS_CONTROLLER.preGrant(ObserverContextImpl.createAndPrepare(CP_ENV),
1259          new UserPermission(USER_RO.getShortName(), Permission.newBuilder(TEST_TABLE)
1260            .withFamily(TEST_FAMILY).withActions(Action.READ).build()),
1261          false);
1262        return null;
1263      }
1264    };
1265
1266    AccessTestAction preRevokeAction = new AccessTestAction() {
1267      @Override
1268      public Object run() throws Exception {
1269        ACCESS_CONTROLLER.preRevoke(ObserverContextImpl.createAndPrepare(CP_ENV),
1270          new UserPermission(USER_RO.getShortName(), Permission.newBuilder(TEST_TABLE)
1271            .withFamily(TEST_FAMILY).withActions(Action.READ).build()));
1272        return null;
1273      }
1274    };
1275
1276    AccessTestAction grantCPAction = new AccessTestAction() {
1277      @Override
1278      public Object run() throws Exception {
1279        try (Connection conn = ConnectionFactory.createConnection(conf);
1280          Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
1281          BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1282          AccessControlService.BlockingInterface protocol =
1283            AccessControlService.newBlockingStub(service);
1284          AccessControlUtil.grant(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY,
1285            null, false, Action.READ);
1286        }
1287        return null;
1288      }
1289    };
1290
1291    AccessTestAction revokeCPAction = new AccessTestAction() {
1292      @Override
1293      public Object run() throws Exception {
1294        try (Connection conn = ConnectionFactory.createConnection(conf);
1295          Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
1296          BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
1297          AccessControlService.BlockingInterface protocol =
1298            AccessControlService.newBlockingStub(service);
1299          AccessControlUtil.revoke(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY,
1300            null, Action.READ);
1301        }
1302        return null;
1303      }
1304    };
1305
1306    verifyAllowed(grantAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1307    verifyDenied(grantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1308      USER_GROUP_WRITE, USER_GROUP_CREATE);
1309    try {
1310      verifyAllowed(revokeAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1311      verifyDenied(revokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1312        USER_GROUP_WRITE, USER_GROUP_CREATE);
1313
1314      verifyAllowed(getTablePermissionsAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1315      verifyDenied(getTablePermissionsAction, USER_CREATE, USER_RW, USER_RO, USER_NONE,
1316        USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1317
1318      verifyAllowed(getGlobalPermissionsAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1319      verifyDenied(getGlobalPermissionsAction, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE,
1320        USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
1321
1322      verifyAllowed(preGrantAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1323      verifyDenied(preGrantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1324        USER_GROUP_WRITE, USER_GROUP_CREATE);
1325
1326      verifyAllowed(preRevokeAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1327      verifyDenied(preRevokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1328        USER_GROUP_WRITE, USER_GROUP_CREATE);
1329
1330      verifyAllowed(grantCPAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1331      verifyDenied(grantCPAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1332        USER_GROUP_WRITE, USER_GROUP_CREATE);
1333
1334      verifyAllowed(revokeCPAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
1335      verifyDenied(revokeCPAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1336        USER_GROUP_WRITE, USER_GROUP_CREATE);
1337    } finally {
1338      // Cleanup, Grant the revoked permission back to the user
1339      grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1340        Permission.Action.READ);
1341    }
1342  }
1343
1344  @Test
1345  public void testPostGrantRevoke() throws Exception {
1346    final TableName tableName = TableName.valueOf("TempTable");
1347    final byte[] family1 = Bytes.toBytes("f1");
1348    final byte[] family2 = Bytes.toBytes("f2");
1349    final byte[] qualifier = Bytes.toBytes("q");
1350
1351    // create table
1352    Admin admin = TEST_UTIL.getAdmin();
1353    if (admin.tableExists(tableName)) {
1354      deleteTable(TEST_UTIL, tableName);
1355    }
1356    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
1357      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family1))
1358      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family2)).build();
1359    createTable(TEST_UTIL, tableDescriptor);
1360    try {
1361      // create temp users
1362      User tblUser =
1363        User.createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]);
1364      User gblUser =
1365        User.createUserForTesting(TEST_UTIL.getConfiguration(), "gbluser", new String[0]);
1366
1367      // prepare actions:
1368      AccessTestAction putActionAll = new AccessTestAction() {
1369        @Override
1370        public Object run() throws Exception {
1371          Put p = new Put(Bytes.toBytes("a"));
1372          p.addColumn(family1, qualifier, Bytes.toBytes("v1"));
1373          p.addColumn(family2, qualifier, Bytes.toBytes("v2"));
1374
1375          try (Connection conn = ConnectionFactory.createConnection(conf);
1376            Table t = conn.getTable(tableName)) {
1377            t.put(p);
1378          }
1379          return null;
1380        }
1381      };
1382
1383      AccessTestAction putAction1 = new AccessTestAction() {
1384        @Override
1385        public Object run() throws Exception {
1386          Put p = new Put(Bytes.toBytes("a"));
1387          p.addColumn(family1, qualifier, Bytes.toBytes("v1"));
1388
1389          try (Connection conn = ConnectionFactory.createConnection(conf);
1390            Table t = conn.getTable(tableName)) {
1391            t.put(p);
1392          }
1393          return null;
1394        }
1395      };
1396
1397      AccessTestAction putAction2 = new AccessTestAction() {
1398        @Override
1399        public Object run() throws Exception {
1400          Put p = new Put(Bytes.toBytes("a"));
1401          p.addColumn(family2, qualifier, Bytes.toBytes("v2"));
1402          try (Connection conn = ConnectionFactory.createConnection(conf);
1403            Table t = conn.getTable(tableName)) {
1404            t.put(p);
1405          }
1406          return null;
1407        }
1408      };
1409
1410      AccessTestAction getActionAll = new AccessTestAction() {
1411        @Override
1412        public Object run() throws Exception {
1413          Get g = new Get(TEST_ROW);
1414          g.addFamily(family1);
1415          g.addFamily(family2);
1416          try (Connection conn = ConnectionFactory.createConnection(conf);
1417            Table t = conn.getTable(tableName)) {
1418            t.get(g);
1419          }
1420          return null;
1421        }
1422      };
1423
1424      AccessTestAction getAction1 = new AccessTestAction() {
1425        @Override
1426        public Object run() throws Exception {
1427          Get g = new Get(TEST_ROW);
1428          g.addFamily(family1);
1429          try (Connection conn = ConnectionFactory.createConnection(conf);
1430            Table t = conn.getTable(tableName)) {
1431            t.get(g);
1432          }
1433          return null;
1434        }
1435      };
1436
1437      AccessTestAction getAction2 = new AccessTestAction() {
1438        @Override
1439        public Object run() throws Exception {
1440          Get g = new Get(TEST_ROW);
1441          g.addFamily(family2);
1442          try (Connection conn = ConnectionFactory.createConnection(conf);
1443            Table t = conn.getTable(tableName)) {
1444            t.get(g);
1445          }
1446          return null;
1447        }
1448      };
1449
1450      AccessTestAction deleteActionAll = new AccessTestAction() {
1451        @Override
1452        public Object run() throws Exception {
1453          Delete d = new Delete(TEST_ROW);
1454          d.addFamily(family1);
1455          d.addFamily(family2);
1456          try (Connection conn = ConnectionFactory.createConnection(conf);
1457            Table t = conn.getTable(tableName)) {
1458            t.delete(d);
1459          }
1460          return null;
1461        }
1462      };
1463
1464      AccessTestAction deleteAction1 = new AccessTestAction() {
1465        @Override
1466        public Object run() throws Exception {
1467          Delete d = new Delete(TEST_ROW);
1468          d.addFamily(family1);
1469          try (Connection conn = ConnectionFactory.createConnection(conf);
1470            Table t = conn.getTable(tableName)) {
1471            t.delete(d);
1472          }
1473          return null;
1474        }
1475      };
1476
1477      AccessTestAction deleteAction2 = new AccessTestAction() {
1478        @Override
1479        public Object run() throws Exception {
1480          Delete d = new Delete(TEST_ROW);
1481          d.addFamily(family2);
1482          try (Connection conn = ConnectionFactory.createConnection(conf);
1483            Table t = conn.getTable(tableName)) {
1484            t.delete(d);
1485          }
1486          return null;
1487        }
1488      };
1489
1490      // initial check:
1491      verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1492      verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1493      verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1494
1495      verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1496      verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1497      verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1498
1499      // grant table read permission
1500      grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1501      grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null,
1502        Permission.Action.READ);
1503
1504      // check
1505      verifyAllowed(tblUser, getActionAll, getAction1, getAction2);
1506      verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1507      verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1508
1509      verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1510      verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1511      verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1512
1513      // grant table write permission while revoking read permissions
1514      grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1515      grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null,
1516        Permission.Action.WRITE);
1517
1518      verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1519      verifyAllowed(tblUser, putActionAll, putAction1, putAction2);
1520      verifyAllowed(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1521
1522      verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1523      verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1524      verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1525
1526      // revoke table permissions
1527      revokeGlobal(TEST_UTIL, gblUser.getShortName());
1528      revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, null, null);
1529
1530      verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1531      verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1532      verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1533
1534      verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1535      verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1536      verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1537
1538      // grant column family read permission
1539      grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.READ);
1540      grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family1, null,
1541        Permission.Action.READ);
1542
1543      // Access should be denied for family2
1544      verifyAllowed(tblUser, getActionAll, getAction1);
1545      verifyDenied(tblUser, getAction2);
1546      verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1547      verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1548
1549      verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1550      verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1551      verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1552
1553      // grant column family write permission
1554      grantGlobal(TEST_UTIL, gblUser.getShortName(), Permission.Action.WRITE);
1555      grantOnTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null,
1556        Permission.Action.WRITE);
1557
1558      // READ from family1, WRITE to family2 are allowed
1559      verifyAllowed(tblUser, getActionAll, getAction1);
1560      verifyAllowed(tblUser, putAction2, deleteAction2);
1561      verifyDenied(tblUser, getAction2);
1562      verifyDenied(tblUser, putActionAll, putAction1);
1563      verifyDenied(tblUser, deleteActionAll, deleteAction1);
1564
1565      verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1566      verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1567      verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1568
1569      // revoke column family permission
1570      revokeGlobal(TEST_UTIL, gblUser.getShortName());
1571      revokeFromTable(TEST_UTIL, tblUser.getShortName(), tableName, family2, null);
1572
1573      // Revoke on family2 should not have impact on family1 permissions
1574      verifyAllowed(tblUser, getActionAll, getAction1);
1575      verifyDenied(tblUser, getAction2);
1576      verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1577      verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1578
1579      // Should not have access as global permissions are completely revoked
1580      verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1581      verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1582      verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1583    } finally {
1584      // delete table
1585      deleteTable(TEST_UTIL, tableName);
1586    }
1587  }
1588
1589  private boolean hasFoundUserPermission(List<UserPermission> userPermissions,
1590    List<UserPermission> perms) {
1591    return perms.containsAll(userPermissions);
1592  }
1593
1594  private boolean hasFoundUserPermission(UserPermission userPermission,
1595    List<UserPermission> perms) {
1596    return perms.contains(userPermission);
1597  }
1598
1599  @Test
1600  public void testPostGrantRevokeAtQualifierLevel() throws Exception {
1601    final TableName tableName = TableName.valueOf(name.getMethodName());
1602    final byte[] family1 = Bytes.toBytes("f1");
1603    final byte[] family2 = Bytes.toBytes("f2");
1604    final byte[] qualifier = Bytes.toBytes("q");
1605
1606    // create table
1607    Admin admin = TEST_UTIL.getAdmin();
1608    if (admin.tableExists(tableName)) {
1609      deleteTable(TEST_UTIL, tableName);
1610    }
1611    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
1612      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family1))
1613      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family2)).build();
1614    createTable(TEST_UTIL, tableDescriptor);
1615
1616    try {
1617      // create temp users
1618      User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1619
1620      AccessTestAction getQualifierAction = new AccessTestAction() {
1621        @Override
1622        public Object run() throws Exception {
1623          Get g = new Get(TEST_ROW);
1624          g.addColumn(family1, qualifier);
1625          try (Connection conn = ConnectionFactory.createConnection(conf);
1626            Table t = conn.getTable(tableName)) {
1627            t.get(g);
1628          }
1629          return null;
1630        }
1631      };
1632
1633      AccessTestAction putQualifierAction = new AccessTestAction() {
1634        @Override
1635        public Object run() throws Exception {
1636          Put p = new Put(TEST_ROW);
1637          p.addColumn(family1, qualifier, Bytes.toBytes("v1"));
1638          try (Connection conn = ConnectionFactory.createConnection(conf);
1639            Table t = conn.getTable(tableName)) {
1640            t.put(p);
1641          }
1642          return null;
1643        }
1644      };
1645
1646      AccessTestAction deleteQualifierAction = new AccessTestAction() {
1647        @Override
1648        public Object run() throws Exception {
1649          Delete d = new Delete(TEST_ROW);
1650          d.addColumn(family1, qualifier);
1651          // d.deleteFamily(family1);
1652          try (Connection conn = ConnectionFactory.createConnection(conf);
1653            Table t = conn.getTable(tableName)) {
1654            t.delete(d);
1655          }
1656          return null;
1657        }
1658      };
1659
1660      revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, null);
1661
1662      verifyDenied(user, getQualifierAction);
1663      verifyDenied(user, putQualifierAction);
1664      verifyDenied(user, deleteQualifierAction);
1665
1666      grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1667        Permission.Action.READ);
1668
1669      verifyAllowed(user, getQualifierAction);
1670      verifyDenied(user, putQualifierAction);
1671      verifyDenied(user, deleteQualifierAction);
1672
1673      // only grant write permission
1674      // TODO: comment this portion after HBASE-3583
1675      grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1676        Permission.Action.WRITE);
1677
1678      verifyDenied(user, getQualifierAction);
1679      verifyAllowed(user, putQualifierAction);
1680      verifyAllowed(user, deleteQualifierAction);
1681
1682      // grant both read and write permission
1683      grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1684        Permission.Action.READ, Permission.Action.WRITE);
1685
1686      verifyAllowed(user, getQualifierAction);
1687      verifyAllowed(user, putQualifierAction);
1688      verifyAllowed(user, deleteQualifierAction);
1689
1690      // revoke family level permission won't impact column level
1691      revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier);
1692
1693      verifyDenied(user, getQualifierAction);
1694      verifyDenied(user, putQualifierAction);
1695      verifyDenied(user, deleteQualifierAction);
1696    } finally {
1697      // delete table
1698      deleteTable(TEST_UTIL, tableName);
1699    }
1700  }
1701
1702  @Test
1703  public void testPermissionList() throws Exception {
1704    final TableName tableName = TableName.valueOf(name.getMethodName());
1705    final byte[] family1 = Bytes.toBytes("f1");
1706    final byte[] family2 = Bytes.toBytes("f2");
1707    final byte[] qualifier = Bytes.toBytes("q");
1708
1709    // create table
1710    Admin admin = TEST_UTIL.getAdmin();
1711    if (admin.tableExists(tableName)) {
1712      deleteTable(TEST_UTIL, tableName);
1713    }
1714    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
1715      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family1))
1716      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family2)).build();
1717    createTable(TEST_UTIL, USER_OWNER, tableDescriptor);
1718    try {
1719      List<UserPermission> perms =
1720        admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build());
1721      UserPermission ownerperm = new UserPermission(USER_OWNER.getName(),
1722        Permission.newBuilder(tableName).withActions(Action.values()).build());
1723      assertTrue("Owner should have all permissions on table",
1724        hasFoundUserPermission(ownerperm, perms));
1725
1726      User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1727      String userName = user.getShortName();
1728
1729      UserPermission up = new UserPermission(userName, Permission.newBuilder(tableName)
1730        .withFamily(family1).withQualifier(qualifier).withActions(Permission.Action.READ).build());
1731      assertFalse("User should not be granted permission: " + up.toString(),
1732        hasFoundUserPermission(up, perms));
1733
1734      // grant read permission
1735      grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1736        Permission.Action.READ);
1737
1738      perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build());
1739      UserPermission upToVerify = new UserPermission(userName, Permission.newBuilder(tableName)
1740        .withFamily(family1).withQualifier(qualifier).withActions(Permission.Action.READ).build());
1741      assertTrue("User should be granted permission: " + upToVerify.toString(),
1742        hasFoundUserPermission(upToVerify, perms));
1743
1744      upToVerify = new UserPermission(userName, Permission.newBuilder(tableName).withFamily(family1)
1745        .withQualifier(qualifier).withActions(Permission.Action.WRITE).build());
1746      assertFalse("User should not be granted permission: " + upToVerify.toString(),
1747        hasFoundUserPermission(upToVerify, perms));
1748
1749      // grant read+write
1750      grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1751        Permission.Action.WRITE, Permission.Action.READ);
1752
1753      perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build());
1754      upToVerify = new UserPermission(userName,
1755        Permission.newBuilder(tableName).withFamily(family1).withQualifier(qualifier)
1756          .withActions(Permission.Action.WRITE, Permission.Action.READ).build());
1757      assertTrue("User should be granted permission: " + upToVerify.toString(),
1758        hasFoundUserPermission(upToVerify, perms));
1759
1760      // revoke
1761      revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier,
1762        Permission.Action.WRITE, Permission.Action.READ);
1763
1764      perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build());
1765      assertFalse("User should not be granted permission: " + upToVerify.toString(),
1766        hasFoundUserPermission(upToVerify, perms));
1767
1768      User newOwner = User.createUserForTesting(conf, "new_owner", new String[] {});
1769      grantOnTable(TEST_UTIL, newOwner.getShortName(), tableName, null, null,
1770        Permission.Action.values());
1771
1772      perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build());
1773      UserPermission newOwnerperm = new UserPermission(newOwner.getName(),
1774        Permission.newBuilder(tableName).withActions(Action.values()).build());
1775      assertTrue("New owner should have all permissions on table",
1776        hasFoundUserPermission(newOwnerperm, perms));
1777    } finally {
1778      // delete table
1779      deleteTable(TEST_UTIL, tableName);
1780    }
1781  }
1782
1783  @Test
1784  public void testGlobalPermissionList() throws Exception {
1785    List<UserPermission> perms = systemUserConnection.getAdmin()
1786      .getUserPermissions(GetUserPermissionsRequest.newBuilder().build());
1787
1788    Collection<String> superUsers = Superusers.getSuperUsers();
1789    List<UserPermission> adminPerms = new ArrayList<>(superUsers.size() + 1);
1790    adminPerms.add(new UserPermission(USER_ADMIN.getShortName(), Permission.newBuilder()
1791      .withActions(Action.ADMIN, Action.CREATE, Action.READ, Action.WRITE).build()));
1792    for (String user : superUsers) {
1793      // Global permission
1794      adminPerms.add(
1795        new UserPermission(user, Permission.newBuilder().withActions(Action.values()).build()));
1796    }
1797    assertTrue(
1798      "Only super users, global users and user admin has permission on table hbase:acl "
1799        + "per setup",
1800      perms.size() == 6 + superUsers.size() && hasFoundUserPermission(adminPerms, perms));
1801  }
1802
1803  /** global operations */
1804  private void verifyGlobal(AccessTestAction action) throws Exception {
1805    verifyAllowed(action, SUPERUSER);
1806
1807    verifyDenied(action, USER_CREATE, USER_RW, USER_NONE, USER_RO);
1808  }
1809
1810  @Test
1811  public void testCheckPermissions() throws Exception {
1812    // --------------------------------------
1813    // test global permissions
1814    AccessTestAction globalAdmin = new AccessTestAction() {
1815      @Override
1816      public Void run() throws Exception {
1817        checkGlobalPerms(TEST_UTIL, Permission.Action.ADMIN);
1818        return null;
1819      }
1820    };
1821    // verify that only superuser can admin
1822    verifyGlobal(globalAdmin);
1823
1824    // --------------------------------------
1825    // test multiple permissions
1826    AccessTestAction globalReadWrite = new AccessTestAction() {
1827      @Override
1828      public Void run() throws Exception {
1829        checkGlobalPerms(TEST_UTIL, Permission.Action.READ, Permission.Action.WRITE);
1830        return null;
1831      }
1832    };
1833
1834    verifyGlobal(globalReadWrite);
1835
1836    // --------------------------------------
1837    // table/column/qualifier level permissions
1838    final byte[] TEST_Q1 = Bytes.toBytes("q1");
1839    final byte[] TEST_Q2 = Bytes.toBytes("q2");
1840
1841    User userTable = User.createUserForTesting(conf, "user_check_perms_table", new String[0]);
1842    User userColumn = User.createUserForTesting(conf, "user_check_perms_family", new String[0]);
1843    User userQualifier = User.createUserForTesting(conf, "user_check_perms_q", new String[0]);
1844
1845    grantOnTable(TEST_UTIL, userTable.getShortName(), TEST_TABLE, null, null,
1846      Permission.Action.READ);
1847    grantOnTable(TEST_UTIL, userColumn.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1848      Permission.Action.READ);
1849    grantOnTable(TEST_UTIL, userQualifier.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_Q1,
1850      Permission.Action.READ);
1851
1852    try {
1853      AccessTestAction tableRead = new AccessTestAction() {
1854        @Override
1855        public Void run() throws Exception {
1856          checkTablePerms(TEST_UTIL, TEST_TABLE, null, null, Permission.Action.READ);
1857          return null;
1858        }
1859      };
1860
1861      AccessTestAction columnRead = new AccessTestAction() {
1862        @Override
1863        public Void run() throws Exception {
1864          checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ);
1865          return null;
1866        }
1867      };
1868
1869      AccessTestAction qualifierRead = new AccessTestAction() {
1870        @Override
1871        public Void run() throws Exception {
1872          checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1873          return null;
1874        }
1875      };
1876
1877      AccessTestAction multiQualifierRead = new AccessTestAction() {
1878        @Override
1879        public Void run() throws Exception {
1880          checkTablePerms(TEST_UTIL,
1881            new Permission[] {
1882              Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_Q1)
1883                .withActions(Permission.Action.READ).build(),
1884              Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_Q2)
1885                .withActions(Permission.Action.READ).build(), });
1886          return null;
1887        }
1888      };
1889
1890      AccessTestAction globalAndTableRead = new AccessTestAction() {
1891        @Override
1892        public Void run() throws Exception {
1893          checkTablePerms(TEST_UTIL, new Permission[] { new Permission(Permission.Action.READ),
1894            Permission.newBuilder(TEST_TABLE).withActions(Permission.Action.READ).build() });
1895          return null;
1896        }
1897      };
1898
1899      AccessTestAction noCheck = new AccessTestAction() {
1900        @Override
1901        public Void run() throws Exception {
1902          checkTablePerms(TEST_UTIL, new Permission[0]);
1903          return null;
1904        }
1905      };
1906
1907      verifyAllowed(tableRead, SUPERUSER, userTable);
1908      verifyDenied(tableRead, userColumn, userQualifier);
1909
1910      verifyAllowed(columnRead, SUPERUSER, userTable, userColumn);
1911      verifyDenied(columnRead, userQualifier);
1912
1913      verifyAllowed(qualifierRead, SUPERUSER, userTable, userColumn, userQualifier);
1914
1915      verifyAllowed(multiQualifierRead, SUPERUSER, userTable, userColumn);
1916      verifyDenied(multiQualifierRead, userQualifier);
1917
1918      verifyAllowed(globalAndTableRead, SUPERUSER);
1919      verifyDenied(globalAndTableRead, userTable, userColumn, userQualifier);
1920
1921      verifyAllowed(noCheck, SUPERUSER, userTable, userColumn, userQualifier);
1922
1923      // --------------------------------------
1924      // test family level multiple permissions
1925      AccessTestAction familyReadWrite = new AccessTestAction() {
1926        @Override
1927        public Void run() throws Exception {
1928          checkTablePerms(TEST_UTIL, TEST_TABLE, TEST_FAMILY, null, Permission.Action.READ,
1929            Permission.Action.WRITE);
1930          return null;
1931        }
1932      };
1933
1934      verifyAllowed(familyReadWrite, SUPERUSER, USER_OWNER, USER_CREATE, USER_RW);
1935      verifyDenied(familyReadWrite, USER_NONE, USER_RO);
1936
1937      // --------------------------------------
1938      // check for wrong table region
1939      CheckPermissionsRequest checkRequest = CheckPermissionsRequest.newBuilder()
1940        .addPermission(AccessControlProtos.Permission.newBuilder()
1941          .setType(AccessControlProtos.Permission.Type.Table)
1942          .setTablePermission(AccessControlProtos.TablePermission.newBuilder()
1943            .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE))
1944            .addAction(AccessControlProtos.Permission.Action.CREATE)))
1945        .build();
1946      Table acl = systemUserConnection.getTable(PermissionStorage.ACL_TABLE_NAME);
1947      try {
1948        BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1949        AccessControlService.BlockingInterface protocol =
1950          AccessControlService.newBlockingStub(channel);
1951        try {
1952          // but ask for TablePermissions for TEST_TABLE
1953          protocol.checkPermissions(null, checkRequest);
1954          fail("this should have thrown CoprocessorException");
1955        } catch (ServiceException ex) {
1956          // expected
1957        }
1958      } finally {
1959        acl.close();
1960      }
1961
1962    } finally {
1963      revokeFromTable(TEST_UTIL, userTable.getShortName(), TEST_TABLE, null, null,
1964        Permission.Action.READ);
1965      revokeFromTable(TEST_UTIL, userColumn.getShortName(), TEST_TABLE, TEST_FAMILY, null,
1966        Permission.Action.READ);
1967      revokeFromTable(TEST_UTIL, userQualifier.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_Q1,
1968        Permission.Action.READ);
1969    }
1970  }
1971
1972  @Test
1973  public void testStopRegionServer() throws Exception {
1974    AccessTestAction action = new AccessTestAction() {
1975      @Override
1976      public Object run() throws Exception {
1977        ACCESS_CONTROLLER.preStopRegionServer(ObserverContextImpl.createAndPrepare(RSCP_ENV));
1978        return null;
1979      }
1980    };
1981
1982    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1983    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1984      USER_GROUP_WRITE, USER_GROUP_CREATE);
1985  }
1986
1987  @Test
1988  public void testRollWALWriterRequest() throws Exception {
1989    AccessTestAction action = new AccessTestAction() {
1990      @Override
1991      public Object run() throws Exception {
1992        ACCESS_CONTROLLER.preRollWALWriterRequest(ObserverContextImpl.createAndPrepare(RSCP_ENV));
1993        return null;
1994      }
1995    };
1996
1997    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
1998    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
1999      USER_GROUP_WRITE, USER_GROUP_CREATE);
2000  }
2001
2002  @Test
2003  public void testOpenRegion() throws Exception {
2004    AccessTestAction action = new AccessTestAction() {
2005      @Override
2006      public Object run() throws Exception {
2007        ACCESS_CONTROLLER.preOpen(ObserverContextImpl.createAndPrepare(RCP_ENV));
2008        return null;
2009      }
2010    };
2011
2012    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2013    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2014      USER_GROUP_READ, USER_GROUP_WRITE);
2015  }
2016
2017  @Test
2018  public void testCloseRegion() throws Exception {
2019    AccessTestAction action = new AccessTestAction() {
2020      @Override
2021      public Object run() throws Exception {
2022        ACCESS_CONTROLLER.preClose(ObserverContextImpl.createAndPrepare(RCP_ENV), false);
2023        return null;
2024      }
2025    };
2026
2027    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2028    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_CREATE,
2029      USER_GROUP_READ, USER_GROUP_WRITE);
2030  }
2031
2032  @Test
2033  public void testSnapshot() throws Exception {
2034    Admin admin = TEST_UTIL.getAdmin();
2035    final TableDescriptor htd = admin.getDescriptor(TEST_TABLE);
2036    final SnapshotDescription snapshot =
2037      new SnapshotDescription(TEST_TABLE.getNameAsString() + "-snapshot", TEST_TABLE);
2038    AccessTestAction snapshotAction = new AccessTestAction() {
2039      @Override
2040      public Object run() throws Exception {
2041        ACCESS_CONTROLLER.preSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot, htd);
2042        return null;
2043      }
2044    };
2045
2046    AccessTestAction deleteAction = new AccessTestAction() {
2047      @Override
2048      public Object run() throws Exception {
2049        ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot);
2050        return null;
2051      }
2052    };
2053
2054    AccessTestAction restoreAction = new AccessTestAction() {
2055      @Override
2056      public Object run() throws Exception {
2057        ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot,
2058          htd);
2059        return null;
2060      }
2061    };
2062
2063    AccessTestAction cloneAction = new AccessTestAction() {
2064      @Override
2065      public Object run() throws Exception {
2066        ACCESS_CONTROLLER.preCloneSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot,
2067          null);
2068        return null;
2069      }
2070    };
2071
2072    verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2073    verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2074      USER_GROUP_WRITE, USER_GROUP_CREATE);
2075
2076    verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2077    verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2078      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2079
2080    verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2081    verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2082      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2083
2084    verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2085    verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_GROUP_READ,
2086      USER_GROUP_WRITE, USER_GROUP_CREATE);
2087  }
2088
2089  @Test
2090  public void testSnapshotWithOwner() throws Exception {
2091    Admin admin = TEST_UTIL.getAdmin();
2092    final TableDescriptor htd = admin.getDescriptor(TEST_TABLE);
2093    final SnapshotDescription snapshot = new SnapshotDescription(
2094      TEST_TABLE.getNameAsString() + "-snapshot", TEST_TABLE, null, USER_OWNER.getName());
2095
2096    AccessTestAction snapshotAction = new AccessTestAction() {
2097      @Override
2098      public Object run() throws Exception {
2099        ACCESS_CONTROLLER.preSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot, htd);
2100        return null;
2101      }
2102    };
2103    verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2104    verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2105      USER_GROUP_WRITE, USER_GROUP_CREATE);
2106
2107    AccessTestAction deleteAction = new AccessTestAction() {
2108      @Override
2109      public Object run() throws Exception {
2110        ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot);
2111        return null;
2112      }
2113    };
2114    verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2115    verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2116      USER_GROUP_WRITE, USER_GROUP_CREATE);
2117
2118    AccessTestAction restoreAction = new AccessTestAction() {
2119      @Override
2120      public Object run() throws Exception {
2121        ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot,
2122          htd);
2123        return null;
2124      }
2125    };
2126    verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2127    verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2128      USER_GROUP_WRITE, USER_GROUP_CREATE);
2129
2130    AccessTestAction cloneAction = new AccessTestAction() {
2131      @Override
2132      public Object run() throws Exception {
2133        ACCESS_CONTROLLER.preCloneSnapshot(ObserverContextImpl.createAndPrepare(CP_ENV), snapshot,
2134          htd);
2135        return null;
2136      }
2137    };
2138    verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER);
2139    verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2140      USER_GROUP_WRITE, USER_GROUP_CREATE);
2141  }
2142
2143  @Test
2144  public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
2145    LOG.debug("Test for global authorization for a new registered RegionServer.");
2146    SingleProcessHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
2147
2148    final Admin admin = TEST_UTIL.getAdmin();
2149    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(TEST_TABLE2)
2150      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
2151    createTable(TEST_UTIL, tableDescriptor);
2152
2153    // Starting a new RegionServer.
2154    JVMClusterUtil.RegionServerThread newRsThread = hbaseCluster.startRegionServer();
2155    final HRegionServer newRs = newRsThread.getRegionServer();
2156
2157    // Move region to the new RegionServer.
2158    List<HRegionLocation> regions;
2159    try (RegionLocator locator = systemUserConnection.getRegionLocator(TEST_TABLE2)) {
2160      regions = locator.getAllRegionLocations();
2161    }
2162    HRegionLocation location = regions.get(0);
2163    final RegionInfo hri = location.getRegion();
2164    final ServerName server = location.getServerName();
2165    try (Table table = systemUserConnection.getTable(TEST_TABLE2)) {
2166      AccessTestAction moveAction = new AccessTestAction() {
2167        @Override
2168        public Object run() throws Exception {
2169          admin.move(hri.getEncodedNameAsBytes(), newRs.getServerName());
2170          return null;
2171        }
2172      };
2173      SUPERUSER.runAs(moveAction);
2174
2175      final int RETRIES_LIMIT = 10;
2176      int retries = 0;
2177      while (newRs.getRegions(TEST_TABLE2).size() < 1 && retries < RETRIES_LIMIT) {
2178        LOG.debug("Waiting for region to be opened. Already retried " + retries + " times.");
2179        try {
2180          Thread.sleep(1000);
2181        } catch (InterruptedException e) {
2182        }
2183        retries++;
2184        if (retries == RETRIES_LIMIT - 1) {
2185          fail("Retry exhaust for waiting region to be opened.");
2186        }
2187      }
2188      // Verify write permission for user "admin2" who has the global
2189      // permissions.
2190      AccessTestAction putAction = new AccessTestAction() {
2191        @Override
2192        public Object run() throws Exception {
2193          Put put = new Put(Bytes.toBytes("test"));
2194          put.addColumn(TEST_FAMILY, Bytes.toBytes("qual"), Bytes.toBytes("value"));
2195          table.put(put);
2196          return null;
2197        }
2198      };
2199      USER_ADMIN.runAs(putAction);
2200    }
2201  }
2202
2203  @Test
2204  public void testTableDescriptorsEnumeration() throws Exception {
2205    User TABLE_ADMIN = User.createUserForTesting(conf, "UserA", new String[0]);
2206
2207    // Grant TABLE ADMIN privs
2208    grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2209      Permission.Action.ADMIN);
2210    try {
2211      AccessTestAction listTablesAction = new AccessTestAction() {
2212        @Override
2213        public Object run() throws Exception {
2214          try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2215            Admin admin = conn.getAdmin()) {
2216            return admin.listTableDescriptors();
2217          }
2218        }
2219      };
2220
2221      AccessTestAction getTableDescAction = new AccessTestAction() {
2222        @Override
2223        public Object run() throws Exception {
2224          try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2225            Admin admin = conn.getAdmin()) {
2226            return admin.getDescriptor(TEST_TABLE);
2227          }
2228        }
2229      };
2230
2231      verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, TABLE_ADMIN,
2232        USER_GROUP_CREATE, USER_GROUP_ADMIN);
2233      verifyIfEmptyList(listTablesAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2234        USER_GROUP_WRITE);
2235
2236      verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, TABLE_ADMIN,
2237        USER_GROUP_CREATE, USER_GROUP_ADMIN);
2238      verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2239        USER_GROUP_WRITE);
2240    } finally {
2241      // Cleanup, revoke TABLE ADMIN privs
2242      revokeFromTable(TEST_UTIL, TABLE_ADMIN.getShortName(), TEST_TABLE, null, null,
2243        Permission.Action.ADMIN);
2244    }
2245  }
2246
2247  @Test
2248  public void testTableNameEnumeration() throws Exception {
2249    AccessTestAction listTablesAction = new AccessTestAction() {
2250      @Override
2251      public Object run() throws Exception {
2252        Connection unmanagedConnection =
2253          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2254        Admin admin = unmanagedConnection.getAdmin();
2255        try {
2256          return Arrays.asList(admin.listTableNames());
2257        } finally {
2258          admin.close();
2259          unmanagedConnection.close();
2260        }
2261      }
2262    };
2263
2264    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW,
2265      USER_RO, USER_GROUP_CREATE, USER_GROUP_ADMIN, USER_GROUP_READ, USER_GROUP_WRITE);
2266    verifyIfEmptyList(listTablesAction, USER_NONE);
2267  }
2268
2269  @Test
2270  public void testTableDeletion() throws Exception {
2271    User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
2272    final TableName tableName = TableName.valueOf(name.getMethodName());
2273    createTestTable(tableName);
2274
2275    // Grant TABLE ADMIN privs
2276    grantOnTable(TEST_UTIL, TABLE_ADMIN.getShortName(), tableName, null, null,
2277      Permission.Action.ADMIN);
2278
2279    AccessTestAction deleteTableAction = new AccessTestAction() {
2280      @Override
2281      public Object run() throws Exception {
2282        Connection unmanagedConnection =
2283          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
2284        Admin admin = unmanagedConnection.getAdmin();
2285        try {
2286          deleteTable(TEST_UTIL, admin, tableName);
2287        } finally {
2288          admin.close();
2289          unmanagedConnection.close();
2290        }
2291        return null;
2292      }
2293    };
2294
2295    verifyDenied(deleteTableAction, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE);
2296    verifyAllowed(deleteTableAction, TABLE_ADMIN);
2297  }
2298
2299  private void createTestTable(TableName tname) throws Exception {
2300    createTestTable(tname, TEST_FAMILY);
2301  }
2302
2303  private void createTestTable(TableName tname, byte[] cf) throws Exception {
2304    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tname)
2305      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(cf).setMaxVersions(100).build())
2306      .build();
2307    createTable(TEST_UTIL, USER_OWNER, tableDescriptor, new byte[][] { Bytes.toBytes("s") });
2308  }
2309
2310  @Test
2311  public void testNamespaceUserGrant() throws Exception {
2312    AccessTestAction getAction = new AccessTestAction() {
2313      @Override
2314      public Object run() throws Exception {
2315        try (Connection conn = ConnectionFactory.createConnection(conf);
2316          Table t = conn.getTable(TEST_TABLE)) {
2317          return t.get(new Get(TEST_ROW));
2318        }
2319      }
2320    };
2321
2322    String namespace = TEST_TABLE.getNamespaceAsString();
2323
2324    // Grant namespace READ to USER_NONE, this should supersede any table permissions
2325    grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2326    // Now USER_NONE should be able to read
2327    verifyAllowed(getAction, USER_NONE);
2328
2329    // Revoke namespace READ to USER_NONE
2330    revokeFromNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2331    verifyDenied(getAction, USER_NONE);
2332  }
2333
2334  @Test
2335  public void testAccessControlClientGrantRevoke() throws Exception {
2336    // Create user for testing, who has no READ privileges by default.
2337    User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2338    AccessTestAction getAction = new AccessTestAction() {
2339      @Override
2340      public Object run() throws Exception {
2341        try (Connection conn = ConnectionFactory.createConnection(conf);
2342          Table t = conn.getTable(TEST_TABLE)) {
2343          return t.get(new Get(TEST_ROW));
2344        }
2345      }
2346    };
2347
2348    verifyDenied(getAction, testGrantRevoke);
2349
2350    // Grant table READ permissions to testGrantRevoke.
2351    try {
2352      grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2353        testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2354    } catch (Throwable e) {
2355      LOG.error("error during call of AccessControlClient.grant. ", e);
2356    }
2357
2358    // Now testGrantRevoke should be able to read also
2359    verifyAllowed(getAction, testGrantRevoke);
2360
2361    // Revoke table READ permission to testGrantRevoke.
2362    try {
2363      revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection,
2364        testGrantRevoke.getShortName(), TEST_TABLE, null, null, Permission.Action.READ);
2365    } catch (Throwable e) {
2366      LOG.error("error during call of AccessControlClient.revoke ", e);
2367    }
2368
2369    // Now testGrantRevoke shouldn't be able read
2370    verifyDenied(getAction, testGrantRevoke);
2371  }
2372
2373  @Test
2374  public void testAccessControlClientGlobalGrantRevoke() throws Exception {
2375    // Create user for testing, who has no READ privileges by default.
2376    User testGlobalGrantRevoke =
2377      User.createUserForTesting(conf, "testGlobalGrantRevoke", new String[0]);
2378    AccessTestAction getAction = new AccessTestAction() {
2379      @Override
2380      public Object run() throws Exception {
2381        try (Connection conn = ConnectionFactory.createConnection(conf);
2382          Table t = conn.getTable(TEST_TABLE)) {
2383          return t.get(new Get(TEST_ROW));
2384        }
2385      }
2386    };
2387
2388    verifyDenied(getAction, testGlobalGrantRevoke);
2389
2390    // Grant table READ permissions to testGlobalGrantRevoke.
2391    String userName = testGlobalGrantRevoke.getShortName();
2392    try {
2393      grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2394        Permission.Action.READ);
2395    } catch (Throwable e) {
2396      LOG.error("error during call of AccessControlClient.grant. ", e);
2397    }
2398    try {
2399      // Now testGlobalGrantRevoke should be able to read also
2400      verifyAllowed(getAction, testGlobalGrantRevoke);
2401    } catch (Exception e) {
2402      revokeGlobal(TEST_UTIL, userName, Permission.Action.READ);
2403      throw e;
2404    }
2405
2406    // Revoke table READ permission to testGlobalGrantRevoke.
2407    try {
2408      revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2409        Permission.Action.READ);
2410    } catch (Throwable e) {
2411      LOG.error("error during call of AccessControlClient.revoke ", e);
2412    }
2413
2414    // Now testGlobalGrantRevoke shouldn't be able read
2415    verifyDenied(getAction, testGlobalGrantRevoke);
2416
2417  }
2418
2419  @Test
2420  public void testAccessControlClientMultiGrantRevoke() throws Exception {
2421    User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
2422    AccessTestAction getAction = new AccessTestAction() {
2423      @Override
2424      public Object run() throws Exception {
2425        try (Connection conn = ConnectionFactory.createConnection(conf);
2426          Table t = conn.getTable(TEST_TABLE)) {
2427          return t.get(new Get(TEST_ROW));
2428        }
2429      }
2430    };
2431
2432    AccessTestAction putAction = new AccessTestAction() {
2433      @Override
2434      public Object run() throws Exception {
2435        Put p = new Put(TEST_ROW);
2436        p.addColumn(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
2437        try (Connection conn = ConnectionFactory.createConnection(conf);
2438          Table t = conn.getTable(TEST_TABLE)) {
2439          t.put(p);
2440          return null;
2441        }
2442      }
2443    };
2444
2445    verifyDenied(getAction, testGrantRevoke);
2446    verifyDenied(putAction, testGrantRevoke);
2447
2448    // Grant global READ permissions to testGrantRevoke.
2449    String userName = testGrantRevoke.getShortName();
2450    try {
2451      grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2452        Permission.Action.READ);
2453    } catch (Throwable e) {
2454      LOG.error("error during call of AccessControlClient.grant. ", e);
2455    }
2456    verifyAllowed(getAction, testGrantRevoke);
2457    verifyDenied(putAction, testGrantRevoke);
2458
2459    // Grant global WRITE permissions to testGrantRevoke.
2460    try {
2461      grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2462        Permission.Action.WRITE);
2463    } catch (Throwable e) {
2464      LOG.error("error during call of AccessControlClient.grant. ", e);
2465    }
2466    verifyAllowed(getAction, testGrantRevoke);
2467    verifyAllowed(putAction, testGrantRevoke);
2468
2469    // Revoke global READ permission to testGrantRevoke.
2470    try {
2471      revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2472        Permission.Action.READ, Permission.Action.WRITE);
2473    } catch (Throwable e) {
2474      LOG.error("error during call of AccessControlClient.revoke ", e);
2475    }
2476    verifyDenied(getAction, testGrantRevoke);
2477    verifyDenied(putAction, testGrantRevoke);
2478
2479    // Grant table READ & WRITE permissions to testGrantRevoke
2480    try {
2481      grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2482        null, null, Permission.Action.READ);
2483    } catch (Throwable e) {
2484      LOG.error("error during call of AccessControlClient.grant. ", e);
2485    }
2486    verifyAllowed(getAction, testGrantRevoke);
2487    verifyDenied(putAction, testGrantRevoke);
2488
2489    // Grant table WRITE permissions to testGrantRevoke
2490    try {
2491      grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2492        null, null, Action.WRITE);
2493    } catch (Throwable e) {
2494      LOG.error("error during call of AccessControlClient.grant. ", e);
2495    }
2496    verifyAllowed(getAction, testGrantRevoke);
2497    verifyAllowed(putAction, testGrantRevoke);
2498
2499    // Revoke table READ & WRITE permission to testGrantRevoke.
2500    try {
2501      revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
2502        null, null, Permission.Action.READ, Permission.Action.WRITE);
2503    } catch (Throwable e) {
2504      LOG.error("error during call of AccessControlClient.revoke ", e);
2505    }
2506    verifyDenied(getAction, testGrantRevoke);
2507    verifyDenied(putAction, testGrantRevoke);
2508
2509    // Grant Namespace READ permissions to testGrantRevoke
2510    String namespace = TEST_TABLE.getNamespaceAsString();
2511    try {
2512      grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, namespace,
2513        Permission.Action.READ);
2514    } catch (Throwable e) {
2515      LOG.error("error during call of AccessControlClient.grant. ", e);
2516    }
2517    verifyAllowed(getAction, testGrantRevoke);
2518    verifyDenied(putAction, testGrantRevoke);
2519
2520    // Grant Namespace WRITE permissions to testGrantRevoke
2521    try {
2522      grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, namespace,
2523        Permission.Action.WRITE);
2524    } catch (Throwable e) {
2525      LOG.error("error during call of AccessControlClient.grant. ", e);
2526    }
2527    verifyAllowed(getAction, testGrantRevoke);
2528    verifyAllowed(putAction, testGrantRevoke);
2529
2530    // Revoke table READ & WRITE permission to testGrantRevoke.
2531    try {
2532      revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2533        TEST_TABLE.getNamespaceAsString(), Permission.Action.READ, Permission.Action.WRITE);
2534    } catch (Throwable e) {
2535      LOG.error("error during call of AccessControlClient.revoke ", e);
2536    }
2537    verifyDenied(getAction, testGrantRevoke);
2538    verifyDenied(putAction, testGrantRevoke);
2539  }
2540
2541  @Test
2542  public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
2543    // Create user for testing, who has no READ privileges by default.
2544    User testNS = User.createUserForTesting(conf, "testNS", new String[0]);
2545    AccessTestAction getAction = new AccessTestAction() {
2546      @Override
2547      public Object run() throws Exception {
2548        try (Connection conn = ConnectionFactory.createConnection(conf);
2549          Table t = conn.getTable(TEST_TABLE)) {
2550          return t.get(new Get(TEST_ROW));
2551        }
2552      }
2553    };
2554
2555    verifyDenied(getAction, testNS);
2556
2557    String userName = testNS.getShortName();
2558    String namespace = TEST_TABLE.getNamespaceAsString();
2559    // Grant namespace READ to testNS, this should supersede any table permissions
2560    try {
2561      grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, namespace,
2562        Permission.Action.READ);
2563    } catch (Throwable e) {
2564      LOG.error("error during call of AccessControlClient.grant. ", e);
2565    }
2566    try {
2567      // Now testNS should be able to read also
2568      verifyAllowed(getAction, testNS);
2569    } catch (Exception e) {
2570      revokeFromNamespace(TEST_UTIL, userName, namespace, Permission.Action.READ);
2571      throw e;
2572    }
2573
2574    // Revoke namespace READ to testNS, this should supersede any table permissions
2575    try {
2576      revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
2577        namespace, Permission.Action.READ);
2578    } catch (Throwable e) {
2579      LOG.error("error during call of AccessControlClient.revoke ", e);
2580    }
2581
2582    // Now testNS shouldn't be able read
2583    verifyDenied(getAction, testNS);
2584  }
2585
2586  public static class PingCoprocessor extends PingService implements RegionCoprocessor {
2587
2588    @Override
2589    public void start(CoprocessorEnvironment env) throws IOException {
2590    }
2591
2592    @Override
2593    public void stop(CoprocessorEnvironment env) throws IOException {
2594    }
2595
2596    @Override
2597    public Iterable<Service> getServices() {
2598      return Collections.singleton(this);
2599    }
2600
2601    @Override
2602    public void ping(RpcController controller, PingRequest request,
2603      RpcCallback<PingResponse> callback) {
2604      callback.run(PingResponse.newBuilder().setPong("Pong!").build());
2605    }
2606
2607    @Override
2608    public void count(RpcController controller, CountRequest request,
2609      RpcCallback<CountResponse> callback) {
2610      callback.run(CountResponse.newBuilder().build());
2611    }
2612
2613    @Override
2614    public void increment(RpcController controller, IncrementCountRequest requet,
2615      RpcCallback<IncrementCountResponse> callback) {
2616      callback.run(IncrementCountResponse.newBuilder().build());
2617    }
2618
2619    @Override
2620    public void hello(RpcController controller, HelloRequest request,
2621      RpcCallback<HelloResponse> callback) {
2622      callback.run(HelloResponse.newBuilder().setResponse("Hello!").build());
2623    }
2624
2625    @Override
2626    public void noop(RpcController controller, NoopRequest request,
2627      RpcCallback<NoopResponse> callback) {
2628      callback.run(NoopResponse.newBuilder().build());
2629    }
2630  }
2631
2632  @Test
2633  public void testCoprocessorExec() throws Exception {
2634    // Set up our ping endpoint service on all regions of our test table
2635    for (JVMClusterUtil.RegionServerThread thread : TEST_UTIL.getMiniHBaseCluster()
2636      .getRegionServerThreads()) {
2637      HRegionServer rs = thread.getRegionServer();
2638      for (HRegion region : rs.getRegions(TEST_TABLE)) {
2639        region.getCoprocessorHost().load(PingCoprocessor.class, Coprocessor.PRIORITY_USER, conf);
2640      }
2641    }
2642
2643    // Create users for testing, and grant EXEC privileges on our test table
2644    // only to user A
2645    User userA = User.createUserForTesting(conf, "UserA", new String[0]);
2646    User userB = User.createUserForTesting(conf, "UserB", new String[0]);
2647
2648    grantOnTable(TEST_UTIL, userA.getShortName(), TEST_TABLE, null, null, Permission.Action.EXEC);
2649    try {
2650      // Create an action for invoking our test endpoint
2651      AccessTestAction execEndpointAction = new AccessTestAction() {
2652        @Override
2653        public Object run() throws Exception {
2654          try (Connection conn = ConnectionFactory.createConnection(conf);
2655            Table t = conn.getTable(TEST_TABLE)) {
2656            BlockingRpcChannel service = t.coprocessorService(HConstants.EMPTY_BYTE_ARRAY);
2657            PingCoprocessor.newBlockingStub(service).noop(null, NoopRequest.newBuilder().build());
2658          }
2659          return null;
2660        }
2661      };
2662
2663      String namespace = TEST_TABLE.getNamespaceAsString();
2664      // Now grant EXEC to the entire namespace to user B
2665      grantOnNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2666      // User B should now be allowed also
2667      verifyAllowed(execEndpointAction, userA, userB);
2668
2669      revokeFromNamespace(TEST_UTIL, userB.getShortName(), namespace, Permission.Action.EXEC);
2670      // Verify that EXEC permission is checked correctly
2671      verifyDenied(execEndpointAction, userB);
2672      verifyAllowed(execEndpointAction, userA);
2673    } finally {
2674      // Cleanup, revoke the userA privileges
2675      revokeFromTable(TEST_UTIL, userA.getShortName(), TEST_TABLE, null, null,
2676        Permission.Action.EXEC);
2677    }
2678  }
2679
2680  @Test
2681  public void testSetQuota() throws Exception {
2682    AccessTestAction setUserQuotaAction = new AccessTestAction() {
2683      @Override
2684      public Object run() throws Exception {
2685        ACCESS_CONTROLLER.preSetUserQuota(ObserverContextImpl.createAndPrepare(CP_ENV), null, null);
2686        return null;
2687      }
2688    };
2689
2690    AccessTestAction setUserTableQuotaAction = new AccessTestAction() {
2691      @Override
2692      public Object run() throws Exception {
2693        ACCESS_CONTROLLER.preSetUserQuota(ObserverContextImpl.createAndPrepare(CP_ENV), null,
2694          TEST_TABLE, null);
2695        return null;
2696      }
2697    };
2698
2699    AccessTestAction setUserNamespaceQuotaAction = new AccessTestAction() {
2700      @Override
2701      public Object run() throws Exception {
2702        ACCESS_CONTROLLER.preSetUserQuota(ObserverContextImpl.createAndPrepare(CP_ENV), null,
2703          (String) null, null);
2704        return null;
2705      }
2706    };
2707
2708    AccessTestAction setTableQuotaAction = new AccessTestAction() {
2709      @Override
2710      public Object run() throws Exception {
2711        ACCESS_CONTROLLER.preSetTableQuota(ObserverContextImpl.createAndPrepare(CP_ENV), TEST_TABLE,
2712          null);
2713        return null;
2714      }
2715    };
2716
2717    AccessTestAction setNamespaceQuotaAction = new AccessTestAction() {
2718      @Override
2719      public Object run() throws Exception {
2720        ACCESS_CONTROLLER.preSetNamespaceQuota(ObserverContextImpl.createAndPrepare(CP_ENV), null,
2721          null);
2722        return null;
2723      }
2724    };
2725
2726    AccessTestAction setRegionServerQuotaAction = new AccessTestAction() {
2727      @Override
2728      public Object run() throws Exception {
2729        ACCESS_CONTROLLER.preSetRegionServerQuota(ObserverContextImpl.createAndPrepare(CP_ENV),
2730          null, null);
2731        return null;
2732      }
2733    };
2734
2735    verifyAllowed(setUserQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2736    verifyDenied(setUserQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2737      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2738
2739    verifyAllowed(setUserTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2740    verifyDenied(setUserTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
2741      USER_GROUP_WRITE, USER_GROUP_CREATE);
2742
2743    verifyAllowed(setUserNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2744    verifyDenied(setUserNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2745      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2746
2747    verifyAllowed(setTableQuotaAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_GROUP_ADMIN);
2748    verifyDenied(setTableQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
2749
2750    verifyAllowed(setNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2751    verifyDenied(setNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2752      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2753
2754    verifyAllowed(setRegionServerQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
2755    verifyDenied(setRegionServerQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2756      USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
2757  }
2758
2759  @Test
2760  public void testGetNamespacePermission() throws Exception {
2761    String namespace = "testGetNamespacePermission";
2762    NamespaceDescriptor desc = NamespaceDescriptor.create(namespace).build();
2763    createNamespace(TEST_UTIL, desc);
2764    grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ);
2765
2766    // Test 1: A specific namespace
2767    getNamespacePermissionsAndVerify(namespace, 1, namespace);
2768
2769    // Test 2: '@.*'
2770    getNamespacePermissionsAndVerify(".*", 1, namespace);
2771
2772    // Test 3: A more complex regex
2773    getNamespacePermissionsAndVerify("^test[a-zA-Z]*", 1, namespace);
2774
2775    deleteNamespace(TEST_UTIL, namespace);
2776  }
2777
2778  /**
2779   * List all user permissions match the given regular expression for namespace and verify each of
2780   * them.
2781   * @param namespaceRegexWithoutPrefix the regualar expression for namespace, without
2782   *                                    NAMESPACE_PREFIX
2783   * @param expectedAmount              the expected amount of user permissions returned
2784   * @param expectedNamespace           the expected namespace of each user permission returned
2785   * @throws HBaseException in the case of any HBase exception when accessing hbase:acl table
2786   */
2787  private void getNamespacePermissionsAndVerify(String namespaceRegexWithoutPrefix,
2788    int expectedAmount, String expectedNamespace) throws HBaseException {
2789    try {
2790      List<UserPermission> namespacePermissions = AccessControlClient.getUserPermissions(
2791        systemUserConnection, PermissionStorage.toNamespaceEntry(namespaceRegexWithoutPrefix));
2792      assertTrue(namespacePermissions != null);
2793      assertEquals(expectedAmount, namespacePermissions.size());
2794      for (UserPermission namespacePermission : namespacePermissions) {
2795        // Verify it is not a global user permission
2796        assertFalse(namespacePermission.getAccessScope() == Permission.Scope.GLOBAL);
2797        // Verify namespace is set
2798        NamespacePermission nsPerm = (NamespacePermission) namespacePermission.getPermission();
2799        assertEquals(expectedNamespace, nsPerm.getNamespace());
2800      }
2801    } catch (Throwable thw) {
2802      throw new HBaseException(thw);
2803    }
2804  }
2805
2806  @Test
2807  public void testTruncatePerms() throws Exception {
2808    try {
2809      List<UserPermission> existingPerms =
2810        AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.getNameAsString());
2811      assertTrue(existingPerms != null);
2812      assertTrue(existingPerms.size() > 1);
2813      TEST_UTIL.getAdmin().disableTable(TEST_TABLE);
2814      TEST_UTIL.truncateTable(TEST_TABLE);
2815      TEST_UTIL.waitTableAvailable(TEST_TABLE);
2816      List<UserPermission> perms =
2817        AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.getNameAsString());
2818      assertTrue(perms != null);
2819      assertEquals(existingPerms.size(), perms.size());
2820    } catch (Throwable e) {
2821      throw new HBaseIOException(e);
2822    }
2823  }
2824
2825  private PrivilegedAction<List<UserPermission>> getPrivilegedAction(final String regex) {
2826    return new PrivilegedAction<List<UserPermission>>() {
2827      @Override
2828      public List<UserPermission> run() {
2829        try (Connection conn = ConnectionFactory.createConnection(conf)) {
2830          return AccessControlClient.getUserPermissions(conn, regex);
2831        } catch (Throwable e) {
2832          LOG.error("error during call of AccessControlClient.getUserPermissions.", e);
2833          return null;
2834        }
2835      }
2836    };
2837  }
2838
2839  @Test
2840  public void testAccessControlClientUserPerms() throws Exception {
2841    final TableName tableName = TableName.valueOf(name.getMethodName());
2842    createTestTable(tableName);
2843    try {
2844      final String regex = tableName.getNameWithNamespaceInclAsString();
2845      User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new String[0]);
2846      assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
2847      // Grant TABLE ADMIN privs to testUserPerms
2848      grantOnTable(TEST_UTIL, testUserPerms.getShortName(), tableName, null, null, Action.ADMIN);
2849      List<UserPermission> perms = testUserPerms.runAs(getPrivilegedAction(regex));
2850      assertNotNull(perms);
2851      // Superuser, testUserPerms
2852      assertEquals(2, perms.size());
2853    } finally {
2854      deleteTable(TEST_UTIL, tableName);
2855    }
2856  }
2857
2858  @Test
2859  public void testAccessControllerUserPermsRegexHandling() throws Exception {
2860    User testRegexHandler = User.createUserForTesting(conf, "testRegexHandling", new String[0]);
2861
2862    final String REGEX_ALL_TABLES = ".*";
2863    final String tableName = name.getMethodName();
2864    final TableName table1 = TableName.valueOf(tableName);
2865    final byte[] family = Bytes.toBytes("f1");
2866
2867    // create table in default ns
2868    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(table1)
2869      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build();
2870    createTable(TEST_UTIL, tableDescriptor);
2871
2872    // creating the ns and table in it
2873    String ns = "testNamespace";
2874    NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
2875    final TableName table2 = TableName.valueOf(ns, tableName);
2876    createNamespace(TEST_UTIL, desc);
2877    tableDescriptor = TableDescriptorBuilder.newBuilder(table2)
2878      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build();
2879    createTable(TEST_UTIL, tableDescriptor);
2880
2881    // Verify that we can read sys-tables
2882    String aclTableName = PermissionStorage.ACL_TABLE_NAME.getNameAsString();
2883    assertEquals(6, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
2884    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
2885
2886    // Grant TABLE ADMIN privs to testUserPerms
2887    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2888    grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, null, Action.ADMIN);
2889    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2890    grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, null, Action.ADMIN);
2891    assertEquals(4, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
2892
2893    // USER_ADMIN, testUserPerms must have a row each.
2894    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
2895    assertEquals(2,
2896      testRegexHandler
2897        .runAs(getPrivilegedAction(
2898          NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + TableName.NAMESPACE_DELIM + tableName))
2899        .size());
2900    assertEquals(2, testRegexHandler
2901      .runAs(getPrivilegedAction(ns + TableName.NAMESPACE_DELIM + tableName)).size());
2902    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
2903
2904    deleteTable(TEST_UTIL, table1);
2905    deleteTable(TEST_UTIL, table2);
2906    deleteNamespace(TEST_UTIL, ns);
2907  }
2908
2909  private void verifyAnyCreate(AccessTestAction action) throws Exception {
2910    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_ADMIN_CF,
2911      USER_GROUP_CREATE, USER_GROUP_ADMIN);
2912    verifyDenied(action, USER_NONE, USER_RO, USER_RW, USER_GROUP_READ, USER_GROUP_WRITE);
2913  }
2914
2915  @Test
2916  public void testPrepareAndCleanBulkLoad() throws Exception {
2917    AccessTestAction prepareBulkLoadAction = new AccessTestAction() {
2918      @Override
2919      public Object run() throws Exception {
2920        ACCESS_CONTROLLER.prePrepareBulkLoad(ObserverContextImpl.createAndPrepare(RCP_ENV));
2921        return null;
2922      }
2923    };
2924    AccessTestAction cleanupBulkLoadAction = new AccessTestAction() {
2925      @Override
2926      public Object run() throws Exception {
2927        ACCESS_CONTROLLER.preCleanupBulkLoad(ObserverContextImpl.createAndPrepare(RCP_ENV));
2928        return null;
2929      }
2930    };
2931    verifyAnyCreate(prepareBulkLoadAction);
2932    verifyAnyCreate(cleanupBulkLoadAction);
2933  }
2934
2935  @Test
2936  public void testReplicateLogEntries() throws Exception {
2937    AccessTestAction replicateLogEntriesAction = new AccessTestAction() {
2938      @Override
2939      public Object run() throws Exception {
2940        ACCESS_CONTROLLER.preReplicateLogEntries(ObserverContextImpl.createAndPrepare(RSCP_ENV));
2941        ACCESS_CONTROLLER.postReplicateLogEntries(ObserverContextImpl.createAndPrepare(RSCP_ENV));
2942        return null;
2943      }
2944    };
2945
2946    verifyAllowed(replicateLogEntriesAction, SUPERUSER, USER_ADMIN, USER_GROUP_WRITE);
2947    verifyDenied(replicateLogEntriesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
2948      USER_GROUP_READ, USER_GROUP_ADMIN, USER_GROUP_CREATE);
2949  }
2950
2951  @Test
2952  public void testAddReplicationPeer() throws Exception {
2953    AccessTestAction action = new AccessTestAction() {
2954      @Override
2955      public Object run() throws Exception {
2956        ACCESS_CONTROLLER.preAddReplicationPeer(ObserverContextImpl.createAndPrepare(CP_ENV),
2957          "test", null);
2958        return null;
2959      }
2960    };
2961
2962    verifyAllowed(action, SUPERUSER, USER_ADMIN);
2963    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
2964  }
2965
2966  @Test
2967  public void testRemoveReplicationPeer() throws Exception {
2968    AccessTestAction action = new AccessTestAction() {
2969      @Override
2970      public Object run() throws Exception {
2971        ACCESS_CONTROLLER.preRemoveReplicationPeer(ObserverContextImpl.createAndPrepare(CP_ENV),
2972          "test");
2973        return null;
2974      }
2975    };
2976
2977    verifyAllowed(action, SUPERUSER, USER_ADMIN);
2978    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
2979  }
2980
2981  @Test
2982  public void testEnableReplicationPeer() throws Exception {
2983    AccessTestAction action = new AccessTestAction() {
2984      @Override
2985      public Object run() throws Exception {
2986        ACCESS_CONTROLLER.preEnableReplicationPeer(ObserverContextImpl.createAndPrepare(CP_ENV),
2987          "test");
2988        return null;
2989      }
2990    };
2991
2992    verifyAllowed(action, SUPERUSER, USER_ADMIN);
2993    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
2994  }
2995
2996  @Test
2997  public void testDisableReplicationPeer() throws Exception {
2998    AccessTestAction action = new AccessTestAction() {
2999      @Override
3000      public Object run() throws Exception {
3001        ACCESS_CONTROLLER.preDisableReplicationPeer(ObserverContextImpl.createAndPrepare(CP_ENV),
3002          "test");
3003        return null;
3004      }
3005    };
3006
3007    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3008    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3009  }
3010
3011  @Test
3012  public void testGetReplicationPeerConfig() throws Exception {
3013    AccessTestAction action = new AccessTestAction() {
3014      @Override
3015      public Object run() throws Exception {
3016        ACCESS_CONTROLLER.preGetReplicationPeerConfig(ObserverContextImpl.createAndPrepare(CP_ENV),
3017          "test");
3018        return null;
3019      }
3020    };
3021
3022    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3023    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3024  }
3025
3026  @Test
3027  public void testUpdateReplicationPeerConfig() throws Exception {
3028    AccessTestAction action = new AccessTestAction() {
3029      @Override
3030      public Object run() throws Exception {
3031        ACCESS_CONTROLLER.preUpdateReplicationPeerConfig(
3032          ObserverContextImpl.createAndPrepare(CP_ENV), "test",
3033          ReplicationPeerConfig.newBuilder().build());
3034        return null;
3035      }
3036    };
3037
3038    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3039    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3040  }
3041
3042  @Test
3043  public void testTransitSyncReplicationPeerState() throws Exception {
3044    AccessTestAction action = new AccessTestAction() {
3045      @Override
3046      public Object run() throws Exception {
3047        ACCESS_CONTROLLER.preTransitReplicationPeerSyncReplicationState(
3048          ObserverContextImpl.createAndPrepare(CP_ENV), "test", SyncReplicationState.NONE);
3049        return null;
3050      }
3051    };
3052
3053    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3054    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3055  }
3056
3057  @Test
3058  public void testListReplicationPeers() throws Exception {
3059    AccessTestAction action = new AccessTestAction() {
3060      @Override
3061      public Object run() throws Exception {
3062        ACCESS_CONTROLLER.preListReplicationPeers(ObserverContextImpl.createAndPrepare(CP_ENV),
3063          "test");
3064        return null;
3065      }
3066    };
3067
3068    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3069    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3070  }
3071
3072  @Test
3073  public void testRemoteLocks() throws Exception {
3074    String namespace = "preQueueNs";
3075    final TableName tableName = TableName.valueOf(namespace, name.getMethodName());
3076    RegionInfo[] regionInfos = new RegionInfo[] { RegionInfoBuilder.newBuilder(tableName).build() };
3077
3078    // Setup Users
3079    // User will be granted ADMIN and CREATE on namespace. Should be denied before grant.
3080    User namespaceUser = User.createUserForTesting(conf, "qLNSUser", new String[0]);
3081    // User will be granted ADMIN and CREATE on table. Should be denied before grant.
3082    User tableACUser = User.createUserForTesting(conf, "qLTableACUser", new String[0]);
3083    // User will be granted READ, WRITE, EXECUTE on table. Should be denied.
3084    User tableRWXUser = User.createUserForTesting(conf, "qLTableRWXUser", new String[0]);
3085    grantOnTable(TEST_UTIL, tableRWXUser.getShortName(), tableName, null, null, Action.READ,
3086      Action.WRITE, Action.EXEC);
3087    // User with global READ, WRITE, EXECUTE should be denied lock access.
3088    User globalRWXUser = User.createUserForTesting(conf, "qLGlobalRWXUser", new String[0]);
3089    grantGlobal(TEST_UTIL, globalRWXUser.getShortName(), Action.READ, Action.WRITE, Action.EXEC);
3090
3091    AccessTestAction namespaceLockAction = new AccessTestAction() {
3092      @Override
3093      public Object run() throws Exception {
3094        ACCESS_CONTROLLER.preRequestLock(ObserverContextImpl.createAndPrepare(CP_ENV), namespace,
3095          null, null, null);
3096        return null;
3097      }
3098    };
3099    verifyAllowed(namespaceLockAction, SUPERUSER, USER_ADMIN);
3100    verifyDenied(namespaceLockAction, globalRWXUser, tableACUser, namespaceUser, tableRWXUser);
3101    grantOnNamespace(TEST_UTIL, namespaceUser.getShortName(), namespace, Action.ADMIN);
3102    // Why I need this pause? I don't need it elsewhere.
3103    Threads.sleep(1000);
3104    verifyAllowed(namespaceLockAction, namespaceUser);
3105
3106    AccessTestAction tableLockAction = new AccessTestAction() {
3107      @Override
3108      public Object run() throws Exception {
3109        ACCESS_CONTROLLER.preRequestLock(ObserverContextImpl.createAndPrepare(CP_ENV), null,
3110          tableName, null, null);
3111        return null;
3112      }
3113    };
3114    verifyAllowed(tableLockAction, SUPERUSER, USER_ADMIN, namespaceUser);
3115    verifyDenied(tableLockAction, globalRWXUser, tableACUser, tableRWXUser);
3116    grantOnTable(TEST_UTIL, tableACUser.getShortName(), tableName, null, null, Action.ADMIN,
3117      Action.CREATE);
3118    // See if this can fail (flakie) because grant hasn't propagated yet.
3119    for (int i = 0; i < 10; i++) {
3120      try {
3121        verifyAllowed(tableLockAction, tableACUser);
3122      } catch (AssertionError e) {
3123        LOG.warn("Retrying assertion error", e);
3124        Threads.sleep(1000);
3125        continue;
3126      }
3127    }
3128
3129    AccessTestAction regionsLockAction = new AccessTestAction() {
3130      @Override
3131      public Object run() throws Exception {
3132        ACCESS_CONTROLLER.preRequestLock(ObserverContextImpl.createAndPrepare(CP_ENV), null, null,
3133          regionInfos, null);
3134        return null;
3135      }
3136    };
3137    verifyAllowed(regionsLockAction, SUPERUSER, USER_ADMIN, namespaceUser, tableACUser);
3138    verifyDenied(regionsLockAction, globalRWXUser, tableRWXUser);
3139
3140    // Test heartbeats
3141    // Create a lock procedure and try sending heartbeat to it. It doesn't matter how the lock
3142    // was created, we just need namespace from the lock's tablename.
3143    LockProcedure proc = new LockProcedure(conf, tableName, LockType.EXCLUSIVE, "test", null);
3144    AccessTestAction regionLockHeartbeatAction = new AccessTestAction() {
3145      @Override
3146      public Object run() throws Exception {
3147        ACCESS_CONTROLLER.preLockHeartbeat(ObserverContextImpl.createAndPrepare(CP_ENV),
3148          proc.getTableName(), proc.getDescription());
3149        return null;
3150      }
3151    };
3152    verifyAllowed(regionLockHeartbeatAction, SUPERUSER, USER_ADMIN, namespaceUser, tableACUser);
3153    verifyDenied(regionLockHeartbeatAction, globalRWXUser, tableRWXUser);
3154  }
3155
3156  @Test
3157  public void testAccessControlRevokeOnlyFewPermission() throws Throwable {
3158    TableName tname = TableName.valueOf("revoke");
3159    try {
3160      TEST_UTIL.createTable(tname, TEST_FAMILY);
3161      User testUserPerms = User.createUserForTesting(conf, "revokePerms", new String[0]);
3162      Permission.Action[] actions = { Action.READ, Action.WRITE };
3163      AccessControlClient.grant(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
3164        null, null, actions);
3165
3166      List<UserPermission> userPermissions =
3167        AccessControlClient.getUserPermissions(TEST_UTIL.getConnection(), tname.getNameAsString());
3168      assertEquals(2, userPermissions.size());
3169
3170      AccessControlClient.revoke(TEST_UTIL.getConnection(), tname, testUserPerms.getShortName(),
3171        null, null, Action.WRITE);
3172
3173      userPermissions =
3174        AccessControlClient.getUserPermissions(TEST_UTIL.getConnection(), tname.getNameAsString());
3175      assertEquals(2, userPermissions.size());
3176
3177      Permission.Action[] expectedAction = { Action.READ };
3178      boolean userFound = false;
3179      for (UserPermission p : userPermissions) {
3180        if (testUserPerms.getShortName().equals(p.getUser())) {
3181          assertArrayEquals(expectedAction, p.getPermission().getActions());
3182          userFound = true;
3183          break;
3184        }
3185      }
3186      assertTrue(userFound);
3187    } finally {
3188      TEST_UTIL.deleteTable(tname);
3189    }
3190  }
3191
3192  @Test
3193  public void testGetClusterStatus() throws Exception {
3194    AccessTestAction action = new AccessTestAction() {
3195      @Override
3196      public Object run() throws Exception {
3197        ACCESS_CONTROLLER.preGetClusterMetrics(ObserverContextImpl.createAndPrepare(CP_ENV));
3198        return null;
3199      }
3200    };
3201
3202    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_RW, USER_RO, USER_NONE,
3203      USER_OWNER);
3204  }
3205
3206  @Test
3207  public void testExecuteProcedures() throws Exception {
3208    AccessTestAction action = new AccessTestAction() {
3209      @Override
3210      public Object run() throws Exception {
3211        ACCESS_CONTROLLER.preExecuteProcedures(ObserverContextImpl.createAndPrepare(RSCP_ENV));
3212        return null;
3213      }
3214    };
3215
3216    verifyAllowed(action, SUPERUSER);
3217    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER, USER_ADMIN);
3218  }
3219
3220  @Test
3221  public void testGetUserPermissions() throws Throwable {
3222    Connection conn = null;
3223    try {
3224      conn = ConnectionFactory.createConnection(conf);
3225      User nSUser1 = User.createUserForTesting(conf, "nsuser1", new String[0]);
3226      User nSUser2 = User.createUserForTesting(conf, "nsuser2", new String[0]);
3227      User nSUser3 = User.createUserForTesting(conf, "nsuser3", new String[0]);
3228
3229      // Global access groups
3230      User globalGroupUser1 =
3231        User.createUserForTesting(conf, "globalGroupUser1", new String[] { "group_admin" });
3232      User globalGroupUser2 = User.createUserForTesting(conf, "globalGroupUser2",
3233        new String[] { "group_admin", "group_create" });
3234      // Namespace access groups
3235      User nsGroupUser1 =
3236        User.createUserForTesting(conf, "nsGroupUser1", new String[] { "ns_group1" });
3237      User nsGroupUser2 =
3238        User.createUserForTesting(conf, "nsGroupUser2", new String[] { "ns_group2" });
3239      // table Access groups
3240      User tableGroupUser1 =
3241        User.createUserForTesting(conf, "tableGroupUser1", new String[] { "table_group1" });
3242      User tableGroupUser2 =
3243        User.createUserForTesting(conf, "tableGroupUser2", new String[] { "table_group2" });
3244
3245      // Create namespaces
3246      String nsPrefix = "testNS";
3247      final String namespace1 = nsPrefix + "1";
3248      NamespaceDescriptor desc1 = NamespaceDescriptor.create(namespace1).build();
3249      createNamespace(TEST_UTIL, desc1);
3250      String namespace2 = nsPrefix + "2";
3251      NamespaceDescriptor desc2 = NamespaceDescriptor.create(namespace2).build();
3252      createNamespace(TEST_UTIL, desc2);
3253
3254      // Grant namespace permission
3255      grantOnNamespace(TEST_UTIL, nSUser1.getShortName(), namespace1, Permission.Action.ADMIN);
3256      grantOnNamespace(TEST_UTIL, nSUser3.getShortName(), namespace1, Permission.Action.READ);
3257      grantOnNamespace(TEST_UTIL, toGroupEntry("ns_group1"), namespace1, Permission.Action.ADMIN);
3258      grantOnNamespace(TEST_UTIL, nSUser2.getShortName(), namespace2, Permission.Action.ADMIN);
3259      grantOnNamespace(TEST_UTIL, nSUser3.getShortName(), namespace2, Permission.Action.ADMIN);
3260      grantOnNamespace(TEST_UTIL, toGroupEntry("ns_group2"), namespace2, Permission.Action.READ,
3261        Permission.Action.WRITE);
3262
3263      // Create tables
3264      TableName table1 = TableName.valueOf(namespace1 + TableName.NAMESPACE_DELIM + "t1");
3265      TableName table2 = TableName.valueOf(namespace2 + TableName.NAMESPACE_DELIM + "t2");
3266      byte[] TEST_FAMILY2 = Bytes.toBytes("f2");
3267      byte[] TEST_QUALIFIER2 = Bytes.toBytes("q2");
3268      createTestTable(table1, TEST_FAMILY);
3269      createTestTable(table2, TEST_FAMILY2);
3270
3271      // Grant table permissions
3272      grantOnTable(TEST_UTIL, toGroupEntry("table_group1"), table1, null, null,
3273        Permission.Action.ADMIN);
3274      grantOnTable(TEST_UTIL, USER_ADMIN.getShortName(), table1, null, null,
3275        Permission.Action.ADMIN);
3276      grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(), table1, TEST_FAMILY, null,
3277        Permission.Action.ADMIN);
3278      grantOnTable(TEST_UTIL, USER_RW.getShortName(), table1, TEST_FAMILY, TEST_QUALIFIER,
3279        Permission.Action.READ);
3280      grantOnTable(TEST_UTIL, USER_RW.getShortName(), table1, TEST_FAMILY, TEST_QUALIFIER2,
3281        Permission.Action.WRITE);
3282
3283      grantOnTable(TEST_UTIL, toGroupEntry("table_group2"), table2, null, null,
3284        Permission.Action.ADMIN);
3285      grantOnTable(TEST_UTIL, USER_ADMIN.getShortName(), table2, null, null,
3286        Permission.Action.ADMIN);
3287      grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(), table2, TEST_FAMILY2, null,
3288        Permission.Action.ADMIN);
3289      grantOnTable(TEST_UTIL, USER_RW.getShortName(), table2, TEST_FAMILY2, TEST_QUALIFIER,
3290        Permission.Action.READ);
3291      grantOnTable(TEST_UTIL, USER_RW.getShortName(), table2, TEST_FAMILY2, TEST_QUALIFIER2,
3292        Permission.Action.WRITE);
3293
3294      List<UserPermission> userPermissions = null;
3295      Collection<String> superUsers = Superusers.getSuperUsers();
3296      int superUserCount = superUsers.size();
3297
3298      // Global User ACL
3299      validateGlobalUserACLForGetUserPermissions(conn, nSUser1, globalGroupUser1, globalGroupUser2,
3300        superUsers, superUserCount);
3301
3302      // Namespace ACL
3303      validateNamespaceUserACLForGetUserPermissions(conn, nSUser1, nSUser3, nsGroupUser1,
3304        nsGroupUser2, nsPrefix, namespace1, namespace2);
3305
3306      // Table + Users
3307      validateTableACLForGetUserPermissions(conn, nSUser1, tableGroupUser1, tableGroupUser2,
3308        nsPrefix, table1, table2, TEST_QUALIFIER2, superUsers);
3309
3310      // exception scenarios
3311
3312      try {
3313        // test case with table name as null
3314        assertEquals(3, AccessControlClient.getUserPermissions(conn, null, TEST_FAMILY).size());
3315        fail("this should have thrown IllegalArgumentException");
3316      } catch (IllegalArgumentException ex) {
3317        // expected
3318      }
3319      try {
3320        // test case with table name as emplty
3321        assertEquals(3, AccessControlClient
3322          .getUserPermissions(conn, HConstants.EMPTY_STRING, TEST_FAMILY).size());
3323        fail("this should have thrown IllegalArgumentException");
3324      } catch (IllegalArgumentException ex) {
3325        // expected
3326      }
3327      try {
3328        // test case with table name as namespace name
3329        assertEquals(3,
3330          AccessControlClient.getUserPermissions(conn, "@" + namespace2, TEST_FAMILY).size());
3331        fail("this should have thrown IllegalArgumentException");
3332      } catch (IllegalArgumentException ex) {
3333        // expected
3334      }
3335
3336      // Clean the table and namespace
3337      deleteTable(TEST_UTIL, table1);
3338      deleteTable(TEST_UTIL, table2);
3339      deleteNamespace(TEST_UTIL, namespace1);
3340      deleteNamespace(TEST_UTIL, namespace2);
3341    } finally {
3342      if (conn != null) {
3343        conn.close();
3344      }
3345    }
3346  }
3347
3348  @Test
3349  public void testHasPermission() throws Throwable {
3350    Connection conn = null;
3351    try {
3352      conn = ConnectionFactory.createConnection(conf);
3353      // Create user and set namespace ACL
3354      User user1 = User.createUserForTesting(conf, "testHasPermissionUser1", new String[0]);
3355      // Grant namespace permission
3356      grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conn, user1.getShortName(),
3357        NamespaceDescriptor.DEFAULT_NAMESPACE.getName(), Permission.Action.ADMIN,
3358        Permission.Action.CREATE, Permission.Action.READ);
3359
3360      // Create user and set table ACL
3361      User user2 = User.createUserForTesting(conf, "testHasPermissionUser2", new String[0]);
3362      // Grant namespace permission
3363      grantOnTableUsingAccessControlClient(TEST_UTIL, conn, user2.getShortName(), TEST_TABLE,
3364        TEST_FAMILY, TEST_QUALIFIER, Permission.Action.READ, Permission.Action.WRITE);
3365
3366      // Verify action privilege
3367      AccessTestAction hasPermissionActionCP = new AccessTestAction() {
3368        @Override
3369        public Object run() throws Exception {
3370          try (Connection conn = ConnectionFactory.createConnection(conf);
3371            Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
3372            BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
3373            AccessControlService.BlockingInterface protocol =
3374              AccessControlService.newBlockingStub(service);
3375            Permission.Action[] actions = { Permission.Action.READ, Permission.Action.WRITE };
3376            AccessControlUtil.hasPermission(null, protocol, TEST_TABLE, TEST_FAMILY,
3377              HConstants.EMPTY_BYTE_ARRAY, "dummy", actions);
3378          }
3379          return null;
3380        }
3381      };
3382      AccessTestAction hasPermissionAction = new AccessTestAction() {
3383        @Override
3384        public Object run() throws Exception {
3385          try (Connection conn = ConnectionFactory.createConnection(conf)) {
3386            Permission.Action[] actions = { Permission.Action.READ, Permission.Action.WRITE };
3387            conn.getAdmin().hasUserPermissions("dummy",
3388              Arrays.asList(Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY)
3389                .withQualifier(HConstants.EMPTY_BYTE_ARRAY).withActions(actions).build()));
3390          }
3391          return null;
3392        }
3393      };
3394      verifyAllowed(hasPermissionActionCP, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER,
3395        USER_ADMIN_CF, user1);
3396      verifyDenied(hasPermissionActionCP, USER_CREATE, USER_RW, USER_RO, USER_NONE, user2);
3397      verifyAllowed(hasPermissionAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER,
3398        USER_ADMIN_CF, user1);
3399      verifyDenied(hasPermissionAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, user2);
3400
3401      // Check for global user
3402      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3403        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN.getShortName(),
3404        Permission.Action.READ, Permission.Action.WRITE, Permission.Action.CREATE,
3405        Permission.Action.ADMIN));
3406      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3407        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN.getShortName(),
3408        Permission.Action.READ, Permission.Action.WRITE, Permission.Action.CREATE,
3409        Permission.Action.ADMIN, Permission.Action.EXEC));
3410
3411      // Check for namespace access user
3412      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3413        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, user1.getShortName(),
3414        Permission.Action.ADMIN, Permission.Action.CREATE));
3415      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3416        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, user1.getShortName(),
3417        Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.EXEC));
3418
3419      // Check for table owner
3420      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3421        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_OWNER.getShortName(),
3422        Permission.Action.READ, Permission.Action.WRITE, Permission.Action.EXEC,
3423        Permission.Action.CREATE, Permission.Action.ADMIN));
3424
3425      // Check for table user
3426      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3427        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_CREATE.getShortName(),
3428        Permission.Action.READ, Permission.Action.WRITE));
3429      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3430        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_RO.getShortName(),
3431        Permission.Action.READ, Permission.Action.WRITE));
3432
3433      // Check for family access user
3434      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3435        HConstants.EMPTY_BYTE_ARRAY, USER_RO.getShortName(), Permission.Action.READ));
3436      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3437        HConstants.EMPTY_BYTE_ARRAY, USER_RW.getShortName(), Permission.Action.READ,
3438        Permission.Action.WRITE));
3439      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3440        HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(),
3441        Permission.Action.ADMIN, Permission.Action.CREATE));
3442      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3443        HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(), Permission.Action.ADMIN,
3444        Permission.Action.CREATE));
3445      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3446        HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(), Permission.Action.READ));
3447
3448      // Check for qualifier access user
3449      assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3450        TEST_QUALIFIER, user2.getShortName(), Permission.Action.READ, Permission.Action.WRITE));
3451      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY,
3452        TEST_QUALIFIER, user2.getShortName(), Permission.Action.EXEC, Permission.Action.READ));
3453      assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3454        HConstants.EMPTY_BYTE_ARRAY, TEST_QUALIFIER, USER_RW.getShortName(),
3455        Permission.Action.WRITE, Permission.Action.READ));
3456
3457      // exception scenarios
3458      try {
3459        // test case with table name as null
3460        assertTrue(AccessControlClient.hasPermission(conn, null, HConstants.EMPTY_BYTE_ARRAY,
3461          HConstants.EMPTY_BYTE_ARRAY, null, Permission.Action.READ));
3462        fail("this should have thrown IllegalArgumentException");
3463      } catch (IllegalArgumentException ex) {
3464        // expected
3465      }
3466      try {
3467        // test case with username as null
3468        assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(),
3469          HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, null, Permission.Action.READ));
3470        fail("this should have thrown IllegalArgumentException");
3471      } catch (IllegalArgumentException ex) {
3472        // expected
3473      }
3474
3475      revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conn, user1.getShortName(),
3476        NamespaceDescriptor.DEFAULT_NAMESPACE.getName(), Permission.Action.ADMIN,
3477        Permission.Action.CREATE, Permission.Action.READ);
3478      revokeFromTableUsingAccessControlClient(TEST_UTIL, conn, user2.getShortName(), TEST_TABLE,
3479        TEST_FAMILY, TEST_QUALIFIER, Permission.Action.READ, Permission.Action.WRITE);
3480    } finally {
3481      if (conn != null) {
3482        conn.close();
3483      }
3484    }
3485  }
3486
3487  @Test
3488  public void testSwitchRpcThrottle() throws Exception {
3489    AccessTestAction action = new AccessTestAction() {
3490      @Override
3491      public Object run() throws Exception {
3492        ACCESS_CONTROLLER.preSwitchRpcThrottle(ObserverContextImpl.createAndPrepare(CP_ENV), true);
3493        return null;
3494      }
3495    };
3496    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3497    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3498  }
3499
3500  @Test
3501  public void testIsRpcThrottleEnabled() throws Exception {
3502    AccessTestAction action = new AccessTestAction() {
3503      @Override
3504      public Object run() throws Exception {
3505        ACCESS_CONTROLLER.preIsRpcThrottleEnabled(ObserverContextImpl.createAndPrepare(CP_ENV));
3506        return null;
3507      }
3508    };
3509    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3510    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3511  }
3512
3513  @Test
3514  public void testSwitchExceedThrottleQuota() throws Exception {
3515    AccessTestAction action = new AccessTestAction() {
3516      @Override
3517      public Object run() throws Exception {
3518        ACCESS_CONTROLLER.preSwitchExceedThrottleQuota(ObserverContextImpl.createAndPrepare(CP_ENV),
3519          true);
3520        return null;
3521      }
3522    };
3523    verifyAllowed(action, SUPERUSER, USER_ADMIN);
3524    verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
3525  }
3526
3527  /*
3528   * Validate Global User ACL
3529   */
3530  private void validateGlobalUserACLForGetUserPermissions(final Connection conn, User nSUser1,
3531    User globalGroupUser1, User globalGroupUser2, Collection<String> superUsers, int superUserCount)
3532    throws Throwable {
3533    // Verify action privilege
3534    AccessTestAction globalUserPermissionAction = new AccessTestAction() {
3535      @Override
3536      public Object run() throws Exception {
3537        try (Connection conn = ConnectionFactory.createConnection(conf)) {
3538          conn.getAdmin().getUserPermissions(
3539            GetUserPermissionsRequest.newBuilder().withUserName("dummy").build());
3540        }
3541        return null;
3542      }
3543    };
3544    verifyAllowed(globalUserPermissionAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
3545    verifyDenied(globalUserPermissionAction, USER_GROUP_CREATE, USER_GROUP_READ, USER_GROUP_WRITE);
3546
3547    // Validate global user permission
3548    List<UserPermission> userPermissions;
3549    assertEquals(6 + superUserCount, AccessControlClient.getUserPermissions(conn, null).size());
3550    assertEquals(6 + superUserCount,
3551      AccessControlClient.getUserPermissions(conn, HConstants.EMPTY_STRING).size());
3552    assertEquals(6 + superUserCount,
3553      AccessControlClient.getUserPermissions(conn, null, HConstants.EMPTY_STRING).size());
3554    userPermissions = AccessControlClient.getUserPermissions(conn, null, USER_ADMIN.getName());
3555    verifyGetUserPermissionResult(userPermissions, 1, null, null, USER_ADMIN.getName(), superUsers);
3556    assertEquals(0, AccessControlClient.getUserPermissions(conn, null, nSUser1.getName()).size());
3557    // Global group user ACL
3558    assertEquals(1,
3559      AccessControlClient.getUserPermissions(conn, null, globalGroupUser1.getName()).size());
3560    assertEquals(2,
3561      AccessControlClient.getUserPermissions(conn, null, globalGroupUser2.getName()).size());
3562  }
3563
3564  /*
3565   * Validate Namespace User ACL
3566   */
3567  private void validateNamespaceUserACLForGetUserPermissions(final Connection conn, User nSUser1,
3568    User nSUser3, User nsGroupUser1, User nsGroupUser2, String nsPrefix, final String namespace1,
3569    String namespace2) throws Throwable {
3570    AccessTestAction namespaceUserPermissionAction = new AccessTestAction() {
3571      @Override
3572      public Object run() throws Exception {
3573        try (Connection conn = ConnectionFactory.createConnection(conf)) {
3574          conn.getAdmin().getUserPermissions(
3575            GetUserPermissionsRequest.newBuilder(namespace1).withUserName("dummy").build());
3576        }
3577        return null;
3578      }
3579    };
3580    verifyAllowed(namespaceUserPermissionAction, SUPERUSER, USER_GROUP_ADMIN, USER_ADMIN, nSUser1,
3581      nsGroupUser1);
3582    verifyDenied(namespaceUserPermissionAction, USER_GROUP_CREATE, USER_GROUP_READ,
3583      USER_GROUP_WRITE, nSUser3, nsGroupUser2);
3584
3585    List<UserPermission> userPermissions;
3586    assertEquals(6, AccessControlClient.getUserPermissions(conn, "@" + nsPrefix + ".*").size());
3587    assertEquals(3, AccessControlClient.getUserPermissions(conn, "@" + namespace1).size());
3588    assertEquals(3, AccessControlClient
3589      .getUserPermissions(conn, "@" + namespace1, HConstants.EMPTY_STRING).size());
3590    userPermissions =
3591      AccessControlClient.getUserPermissions(conn, "@" + namespace1, nSUser1.getName());
3592    verifyGetUserPermissionResult(userPermissions, 1, null, null, nSUser1.getName(), null);
3593    userPermissions =
3594      AccessControlClient.getUserPermissions(conn, "@" + namespace1, nSUser3.getName());
3595    verifyGetUserPermissionResult(userPermissions, 1, null, null, nSUser3.getName(), null);
3596    assertEquals(0,
3597      AccessControlClient.getUserPermissions(conn, "@" + namespace1, USER_ADMIN.getName()).size());
3598    // Namespace group user ACL
3599    assertEquals(1, AccessControlClient
3600      .getUserPermissions(conn, "@" + namespace1, nsGroupUser1.getName()).size());
3601    assertEquals(1, AccessControlClient
3602      .getUserPermissions(conn, "@" + namespace2, nsGroupUser2.getName()).size());
3603  }
3604
3605  /*
3606   * Validate Table User ACL
3607   */
3608  private void validateTableACLForGetUserPermissions(final Connection conn, User nSUser1,
3609    User tableGroupUser1, User tableGroupUser2, String nsPrefix, TableName table1, TableName table2,
3610    byte[] TEST_QUALIFIER2, Collection<String> superUsers) throws Throwable {
3611    AccessTestAction tableUserPermissionAction = new AccessTestAction() {
3612      @Override
3613      public Object run() throws Exception {
3614        try (Connection conn = ConnectionFactory.createConnection(conf)) {
3615          conn.getAdmin().getUserPermissions(GetUserPermissionsRequest.newBuilder(TEST_TABLE)
3616            .withFamily(TEST_FAMILY).withQualifier(TEST_QUALIFIER).withUserName("dummy").build());
3617        }
3618        return null;
3619      }
3620    };
3621    verifyAllowed(tableUserPermissionAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_ADMIN_CF);
3622    verifyDenied(tableUserPermissionAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_CREATE);
3623
3624    List<UserPermission> userPermissions;
3625    assertEquals(12, AccessControlClient.getUserPermissions(conn, nsPrefix + ".*").size());
3626    assertEquals(6, AccessControlClient.getUserPermissions(conn, table1.getNameAsString()).size());
3627    assertEquals(6, AccessControlClient
3628      .getUserPermissions(conn, table1.getNameAsString(), HConstants.EMPTY_STRING).size());
3629    userPermissions = AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3630      USER_ADMIN_CF.getName());
3631    verifyGetUserPermissionResult(userPermissions, 1, null, null, USER_ADMIN_CF.getName(), null);
3632    assertEquals(0, AccessControlClient
3633      .getUserPermissions(conn, table1.getNameAsString(), nSUser1.getName()).size());
3634    // Table group user ACL
3635    assertEquals(1, AccessControlClient
3636      .getUserPermissions(conn, table1.getNameAsString(), tableGroupUser1.getName()).size());
3637    assertEquals(1, AccessControlClient
3638      .getUserPermissions(conn, table2.getNameAsString(), tableGroupUser2.getName()).size());
3639
3640    // Table Users + CF
3641    assertEquals(12, AccessControlClient
3642      .getUserPermissions(conn, nsPrefix + ".*", HConstants.EMPTY_BYTE_ARRAY).size());
3643    userPermissions = AccessControlClient.getUserPermissions(conn, nsPrefix + ".*", TEST_FAMILY);
3644    verifyGetUserPermissionResult(userPermissions, 3, TEST_FAMILY, null, null, null);
3645    assertEquals(0, AccessControlClient
3646      .getUserPermissions(conn, table1.getNameAsString(), Bytes.toBytes("dummmyCF")).size());
3647
3648    // Table Users + CF + User
3649    assertEquals(3,
3650      AccessControlClient
3651        .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_STRING)
3652        .size());
3653    userPermissions = AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3654      TEST_FAMILY, USER_ADMIN_CF.getName());
3655    verifyGetUserPermissionResult(userPermissions, 1, null, null, USER_ADMIN_CF.getName(),
3656      superUsers);
3657    assertEquals(0, AccessControlClient
3658      .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, nSUser1.getName()).size());
3659
3660    // Table Users + CF + CQ
3661    assertEquals(3, AccessControlClient
3662      .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY)
3663      .size());
3664    assertEquals(1, AccessControlClient
3665      .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, TEST_QUALIFIER).size());
3666    assertEquals(1, AccessControlClient
3667      .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, TEST_QUALIFIER2).size());
3668    assertEquals(2, AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3669      HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_RW.getName()).size());
3670    assertEquals(0,
3671      AccessControlClient
3672        .getUserPermissions(conn, table1.getNameAsString(), TEST_FAMILY, Bytes.toBytes("dummmyCQ"))
3673        .size());
3674
3675    // Table Users + CF + CQ + User
3676    assertEquals(3, AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3677      TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_STRING).size());
3678    assertEquals(1, AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3679      TEST_FAMILY, TEST_QUALIFIER, USER_RW.getName()).size());
3680    assertEquals(1, AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3681      TEST_FAMILY, TEST_QUALIFIER2, USER_RW.getName()).size());
3682    assertEquals(0, AccessControlClient.getUserPermissions(conn, table1.getNameAsString(),
3683      TEST_FAMILY, TEST_QUALIFIER2, nSUser1.getName()).size());
3684  }
3685
3686  /*
3687   * Validate the user permission against the specified column family, column qualifier and user
3688   * name.
3689   */
3690  private void verifyGetUserPermissionResult(List<UserPermission> userPermissions, int resultCount,
3691    byte[] cf, byte[] cq, String userName, Collection<String> superUsers) {
3692    assertEquals(resultCount, userPermissions.size());
3693
3694    for (UserPermission perm : userPermissions) {
3695      if (perm.getPermission() instanceof TablePermission) {
3696        TablePermission tablePerm = (TablePermission) perm.getPermission();
3697        if (cf != null) {
3698          assertTrue(Bytes.equals(cf, tablePerm.getFamily()));
3699        }
3700        if (cq != null) {
3701          assertTrue(Bytes.equals(cq, tablePerm.getQualifier()));
3702        }
3703        if (userName != null && (superUsers == null || !superUsers.contains(perm.getUser()))) {
3704          assertTrue(userName.equals(perm.getUser()));
3705        }
3706      } else if (
3707        perm.getPermission() instanceof NamespacePermission
3708          || perm.getPermission() instanceof GlobalPermission
3709      ) {
3710        if (userName != null && (superUsers == null || !superUsers.contains(perm.getUser()))) {
3711          assertTrue(userName.equals(perm.getUser()));
3712        }
3713      }
3714    }
3715  }
3716
3717  /*
3718   * Dummy ShellBasedUnixGroupsMapping class to retrieve the groups for the test users.
3719   */
3720  public static class MyShellBasedUnixGroupsMapping extends ShellBasedUnixGroupsMapping
3721    implements GroupMappingServiceProvider {
3722    @Override
3723    public List<String> getGroups(String user) throws IOException {
3724      if (user.equals("globalGroupUser1")) {
3725        return Arrays.asList(new String[] { "group_admin" });
3726      } else if (user.equals("globalGroupUser2")) {
3727        return Arrays.asList(new String[] { "group_admin", "group_create" });
3728      } else if (user.equals("nsGroupUser1")) {
3729        return Arrays.asList(new String[] { "ns_group1" });
3730      } else if (user.equals("nsGroupUser2")) {
3731        return Arrays.asList(new String[] { "ns_group2" });
3732      } else if (user.equals("tableGroupUser1")) {
3733        return Arrays.asList(new String[] { "table_group1" });
3734      } else if (user.equals("tableGroupUser2")) {
3735        return Arrays.asList(new String[] { "table_group2" });
3736      } else {
3737        return super.getGroups(user);
3738      }
3739    }
3740  }
3741}