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