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