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