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