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