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