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