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