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