/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hbase.security.access; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.Coprocessor; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Append; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Durability; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.Increment; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment; import org.apache.hadoop.hbase.filter.BinaryComparator; import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas; import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; import org.apache.hadoop.hbase.regionserver.Region; import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost; import org.apache.hadoop.hbase.regionserver.RegionScanner; import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.access.Permission.Action; import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.SecurityTests; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.TestTableName; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import com.google.common.collect.Lists; @Category({SecurityTests.class, LargeTests.class}) public class TestWithDisabledAuthorization extends SecureTestUtil { private static final Log LOG = LogFactory.getLog(TestWithDisabledAuthorization.class); static { Logger.getLogger(AccessController.class).setLevel(Level.TRACE); Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE); Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE); } private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); private static final byte[] TEST_FAMILY = Bytes.toBytes("f1"); private static final byte[] TEST_FAMILY2 = Bytes.toBytes("f2"); private static final byte[] TEST_ROW = Bytes.toBytes("testrow"); private static final byte[] TEST_Q1 = Bytes.toBytes("q1"); private static final byte[] TEST_Q2 = Bytes.toBytes("q2"); private static final byte[] TEST_Q3 = Bytes.toBytes("q3"); private static final byte[] TEST_Q4 = Bytes.toBytes("q4"); private static final byte[] ZERO = Bytes.toBytes(0L); private static MasterCoprocessorEnvironment CP_ENV; private static AccessController ACCESS_CONTROLLER; private static RegionServerCoprocessorEnvironment RSCP_ENV; private RegionCoprocessorEnvironment RCP_ENV; @Rule public TestTableName TEST_TABLE = new TestTableName(); // default users // superuser private static User SUPERUSER; // user granted with all global permission private static User USER_ADMIN; // user with rw permissions on column family. private static User USER_RW; // user with read-only permissions private static User USER_RO; // user is table owner. will have all permissions on table private static User USER_OWNER; // user with create table permissions alone private static User USER_CREATE; // user with no permissions private static User USER_NONE; // user with only partial read-write perms (on family:q1 only) private static User USER_QUAL; @BeforeClass public static void setupBeforeClass() throws Exception { Configuration conf = TEST_UTIL.getConfiguration(); // Up the handlers; this test needs more than usual. TEST_UTIL.getConfiguration().setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10); // Enable security enableSecurity(conf); // We expect 0.98 cell ACL semantics conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); // Enable EXEC permission checking conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true); // Verify enableSecurity sets up what we require verifyConfiguration(conf); // Now, DISABLE only active authorization conf.setBoolean(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, false); // Start the minicluster TEST_UTIL.startMiniCluster(); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(AccessController.class.getName()); CP_ENV = cpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf); RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0) .getRegionServerCoprocessorHost(); RSCP_ENV = rsHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); // create a set of test users SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]); USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]); USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]); USER_RO = User.createUserForTesting(conf, "rouser", new String[0]); USER_QUAL = User.createUserForTesting(conf, "rwpartial", new String[0]); USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]); } @AfterClass public static void tearDownAfterClass() throws Exception { TEST_UTIL.shutdownMiniCluster(); } @Before public void setUp() throws Exception { // Create the test table (owner added to the _acl_ table) Admin admin = TEST_UTIL.getAdmin(); HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY); hcd.setMaxVersions(100); htd.addFamily(hcd); htd.setOwner(USER_OWNER); admin.createTable(htd, new byte[][] { Bytes.toBytes("s") }); TEST_UTIL.waitUntilAllRegionsAssigned(TEST_TABLE.getTableName()); Region region = TEST_UTIL.getHBaseCluster().getRegions(TEST_TABLE.getTableName()).get(0); RegionCoprocessorHost rcpHost = region.getCoprocessorHost(); RCP_ENV = rcpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, TEST_UTIL.getConfiguration()); // Set up initial grants grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(), Permission.Action.ADMIN, Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE); grantOnTable(TEST_UTIL, USER_RW.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ, Permission.Action.WRITE); // USER_CREATE is USER_RW plus CREATE permissions grantOnTable(TEST_UTIL, USER_CREATE.getShortName(), TEST_TABLE.getTableName(), null, null, Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE); grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ); grantOnTable(TEST_UTIL, USER_QUAL.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ, Permission.Action.WRITE); assertEquals(5, AccessControlLists.getTablePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName()).size()); } @After public void tearDown() throws Exception { // Clean the _acl_ table try { deleteTable(TEST_UTIL, TEST_TABLE.getTableName()); } catch (TableNotFoundException ex) { // Test deleted the table, no problem LOG.info("Test deleted table " + TEST_TABLE.getTableName()); } // Verify all table/namespace permissions are erased assertEquals(0, AccessControlLists.getTablePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName()).size()); assertEquals(0, AccessControlLists.getNamespacePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName().getNamespaceAsString()).size()); } @Test public void testCheckPermissions() throws Exception { AccessTestAction checkGlobalAdmin = new AccessTestAction() { @Override public Void run() throws Exception { checkGlobalPerms(TEST_UTIL, Permission.Action.ADMIN); return null; } }; verifyAllowed(checkGlobalAdmin, SUPERUSER, USER_ADMIN); verifyDenied(checkGlobalAdmin, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkGlobalRead = new AccessTestAction() { @Override public Void run() throws Exception { checkGlobalPerms(TEST_UTIL, Permission.Action.READ); return null; } }; verifyAllowed(checkGlobalRead, SUPERUSER, USER_ADMIN); verifyDenied(checkGlobalRead, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkGlobalReadWrite = new AccessTestAction() { @Override public Void run() throws Exception { checkGlobalPerms(TEST_UTIL, Permission.Action.READ, Permission.Action.WRITE); return null; } }; verifyAllowed(checkGlobalReadWrite, SUPERUSER, USER_ADMIN); verifyDenied(checkGlobalReadWrite, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkTableAdmin = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), null, null, Permission.Action.ADMIN); return null; } }; verifyAllowed(checkTableAdmin, SUPERUSER, USER_ADMIN, USER_OWNER); verifyDenied(checkTableAdmin, USER_CREATE, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkTableCreate = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), null, null, Permission.Action.CREATE); return null; } }; verifyAllowed(checkTableCreate, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE); verifyDenied(checkTableCreate, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkTableRead = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), null, null, Permission.Action.READ); return null; } }; verifyAllowed(checkTableRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE); verifyDenied(checkTableRead, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkTableReadWrite = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), null, null, Permission.Action.READ, Permission.Action.WRITE); return null; } }; verifyAllowed(checkTableReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE); verifyDenied(checkTableReadWrite, USER_RW, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkColumnRead = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ); return null; } }; verifyAllowed(checkColumnRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO); verifyDenied(checkColumnRead, USER_QUAL, USER_NONE); AccessTestAction checkColumnReadWrite = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ, Permission.Action.WRITE); return null; } }; verifyAllowed(checkColumnReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW); verifyDenied(checkColumnReadWrite, USER_RO, USER_QUAL, USER_NONE); AccessTestAction checkQualifierRead = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ); return null; } }; verifyAllowed(checkQualifierRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL); verifyDenied(checkQualifierRead, USER_NONE); AccessTestAction checkQualifierReadWrite = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ, Permission.Action.WRITE); return null; } }; verifyAllowed(checkQualifierReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_QUAL); verifyDenied(checkQualifierReadWrite, USER_RO, USER_NONE); AccessTestAction checkMultiQualifierRead = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), new Permission[] { new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ), new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q2, Permission.Action.READ), }); return null; } }; verifyAllowed(checkMultiQualifierRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO); verifyDenied(checkMultiQualifierRead, USER_QUAL, USER_NONE); AccessTestAction checkMultiQualifierReadWrite = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), new Permission[] { new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ, Permission.Action.WRITE), new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q2, Permission.Action.READ, Permission.Action.WRITE), }); return null; } }; verifyAllowed(checkMultiQualifierReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW); verifyDenied(checkMultiQualifierReadWrite, USER_RO, USER_QUAL, USER_NONE); } /** Test grants and revocations with authorization disabled */ @Test public void testPassiveGrantRevoke() throws Exception { // Add a test user User tblUser = User.createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]); // If we check now, the test user won't have permissions AccessTestAction checkTableRead = new AccessTestAction() { @Override public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ); return null; } }; verifyDenied(tblUser, checkTableRead); // An actual read won't be denied AccessTestAction tableRead = new AccessTestAction() { @Override public Void run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration()); Table t = conn.getTable(TEST_TABLE.getTableName())) { t.get(new Get(TEST_ROW).addFamily(TEST_FAMILY)); } return null; } }; verifyAllowed(tblUser, tableRead); // Grant read perms to the test user grantOnTable(TEST_UTIL, tblUser.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ); // Now both the permission check and actual op will succeed verifyAllowed(tblUser, checkTableRead); verifyAllowed(tblUser, tableRead); // Revoke read perms from the test user revokeFromTable(TEST_UTIL, tblUser.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ); // Now the permission check will indicate revocation but the actual op will still succeed verifyDenied(tblUser, checkTableRead); verifyAllowed(tblUser, tableRead); } /** Test master observer */ @Test public void testPassiveMasterOperations() throws Exception { // preCreateTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); htd.addFamily(new HColumnDescriptor(TEST_FAMILY)); ACCESS_CONTROLLER.preCreateTable(ObserverContext.createAndPrepare(CP_ENV, null), htd, null); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preModifyTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); htd.addFamily(new HColumnDescriptor(TEST_FAMILY)); htd.addFamily(new HColumnDescriptor(TEST_FAMILY2)); ACCESS_CONTROLLER.preModifyTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), htd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDeleteTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDeleteTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName()); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preTruncateTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preTruncateTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName()); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preAddColumnFamily verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY2); ACCESS_CONTROLLER.preAddColumnFamily(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), hcd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preModifyColumnFamily verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY2); ACCESS_CONTROLLER.preModifyColumnFamily(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), hcd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDeleteColumnFamily verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDeleteColumnFamily(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), TEST_FAMILY2); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preEnableTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName()); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDisableTable verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName()); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preMove verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HRegionInfo region = new HRegionInfo(TEST_TABLE.getTableName()); ServerName srcServer = ServerName.valueOf("1.1.1.1", 1, 0); ServerName destServer = ServerName.valueOf("2.2.2.2", 2, 0); ACCESS_CONTROLLER.preMove(ObserverContext.createAndPrepare(CP_ENV, null), region, srcServer, destServer); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preAssign verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HRegionInfo region = new HRegionInfo(TEST_TABLE.getTableName()); ACCESS_CONTROLLER.preAssign(ObserverContext.createAndPrepare(CP_ENV, null), region); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preUnassign verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HRegionInfo region = new HRegionInfo(TEST_TABLE.getTableName()); ACCESS_CONTROLLER.preUnassign(ObserverContext.createAndPrepare(CP_ENV, null), region, true); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preBalance verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preBalance(ObserverContext.createAndPrepare(CP_ENV, null)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preBalanceSwitch verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preBalanceSwitch(ObserverContext.createAndPrepare(CP_ENV, null), true); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preSnapshot verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { SnapshotDescription snapshot = SnapshotDescription.newBuilder() .setName("foo") .build(); HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null), snapshot, htd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preListSnapshot verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { SnapshotDescription snapshot = SnapshotDescription.newBuilder() .setName("foo") .build(); ACCESS_CONTROLLER.preListSnapshot(ObserverContext.createAndPrepare(CP_ENV, null), snapshot); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preCloneSnapshot verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { SnapshotDescription snapshot = SnapshotDescription.newBuilder() .setName("foo") .build(); HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null), snapshot, htd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preRestoreSnapshot verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { SnapshotDescription snapshot = SnapshotDescription.newBuilder() .setName("foo") .build(); HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null), snapshot, htd); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDeleteSnapshot verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { SnapshotDescription snapshot = SnapshotDescription.newBuilder() .setName("foo") .build(); ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null), snapshot); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preGetTableDescriptors verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { List<TableName> tableNamesList = Lists.newArrayList(); tableNamesList.add(TEST_TABLE.getTableName()); List<HTableDescriptor> descriptors = Lists.newArrayList(); ACCESS_CONTROLLER.preGetTableDescriptors(ObserverContext.createAndPrepare(CP_ENV, null), tableNamesList, descriptors, ".+"); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preGetTableNames verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { List<HTableDescriptor> descriptors = Lists.newArrayList(); ACCESS_CONTROLLER.preGetTableNames(ObserverContext.createAndPrepare(CP_ENV, null), descriptors, ".+"); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preCreateNamespace verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { NamespaceDescriptor ns = NamespaceDescriptor.create("test").build(); ACCESS_CONTROLLER.preCreateNamespace(ObserverContext.createAndPrepare(CP_ENV, null), ns); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDeleteNamespace verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDeleteNamespace(ObserverContext.createAndPrepare(CP_ENV, null), "test"); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preModifyNamespace verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { NamespaceDescriptor ns = NamespaceDescriptor.create("test").build(); ACCESS_CONTROLLER.preModifyNamespace(ObserverContext.createAndPrepare(CP_ENV, null), ns); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preGetNamespaceDescriptor verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preGetNamespaceDescriptor(ObserverContext.createAndPrepare(CP_ENV, null), "test"); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preListNamespaceDescriptors verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { List<NamespaceDescriptor> descriptors = Lists.newArrayList(); ACCESS_CONTROLLER.preListNamespaceDescriptors(ObserverContext.createAndPrepare(CP_ENV, null), descriptors); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preSplit verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preSplitRegion( ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), Bytes.toBytes("ss")); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preSetUserQuota verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { Quotas quotas = Quotas.newBuilder().build(); ACCESS_CONTROLLER.preSetUserQuota(ObserverContext.createAndPrepare(CP_ENV, null), "testuser", quotas); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preSetTableQuota verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { Quotas quotas = Quotas.newBuilder().build(); ACCESS_CONTROLLER.preSetTableQuota(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(), quotas); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preSetNamespaceQuota verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { Quotas quotas = Quotas.newBuilder().build(); ACCESS_CONTROLLER.preSetNamespaceQuota(ObserverContext.createAndPrepare(CP_ENV, null), "test", quotas); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); } /** Test region server observer */ @Test public void testPassiveRegionServerOperations() throws Exception { // preStopRegionServer verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preStopRegionServer(ObserverContext.createAndPrepare(RSCP_ENV, null)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preMerge verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName()); Region region_a = mock(Region.class); when(region_a.getTableDesc()).thenReturn(htd); Region region_b = mock(Region.class); when(region_b.getTableDesc()).thenReturn(htd); ACCESS_CONTROLLER.preMerge(ObserverContext.createAndPrepare(RSCP_ENV, null), region_a, region_b); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preRollWALWriterRequest verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preRollWALWriterRequest(ObserverContext.createAndPrepare(RSCP_ENV, null)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); } /** Test region observer */ @Test public void testPassiveRegionOperations() throws Exception { // preOpen verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preOpen(ObserverContext.createAndPrepare(RCP_ENV, null)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preFlush verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preFlush(ObserverContext.createAndPrepare(RCP_ENV, null)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preGetOp verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { List<Cell> cells = Lists.newArrayList(); ACCESS_CONTROLLER.preGetOp(ObserverContext.createAndPrepare(RCP_ENV, null), new Get(TEST_ROW), cells); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preExists verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preExists(ObserverContext.createAndPrepare(RCP_ENV, null), new Get(TEST_ROW), true); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // prePut verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.prePut(ObserverContext.createAndPrepare(RCP_ENV, null), new Put(TEST_ROW), new WALEdit(), Durability.USE_DEFAULT); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preDelete verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDelete(ObserverContext.createAndPrepare(RCP_ENV, null), new Delete(TEST_ROW), new WALEdit(), Durability.USE_DEFAULT); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preBatchMutate verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preBatchMutate(ObserverContext.createAndPrepare(RCP_ENV, null), new MiniBatchOperationInProgress<>(null, null, null, 0, 0)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preCheckAndPut verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preCheckAndPut(ObserverContext.createAndPrepare(RCP_ENV, null), TEST_ROW, TEST_FAMILY, TEST_Q1, CompareFilter.CompareOp.EQUAL, new BinaryComparator("foo".getBytes()), new Put(TEST_ROW), true); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preCheckAndDelete verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preCheckAndDelete(ObserverContext.createAndPrepare(RCP_ENV, null), TEST_ROW, TEST_FAMILY, TEST_Q1, CompareFilter.CompareOp.EQUAL, new BinaryComparator("foo".getBytes()), new Delete(TEST_ROW), true); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preAppend verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preAppend(ObserverContext.createAndPrepare(RCP_ENV, null), new Append(TEST_ROW)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preIncrement verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preIncrement(ObserverContext.createAndPrepare(RCP_ENV, null), new Increment(TEST_ROW)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preScannerOpen verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preScannerOpen(ObserverContext.createAndPrepare(RCP_ENV, null), new Scan(), mock(RegionScanner.class)); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); // preBulkLoadHFile verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { List<Pair<byte[], String>> paths = Lists.newArrayList(); ACCESS_CONTROLLER.preBulkLoadHFile(ObserverContext.createAndPrepare(RCP_ENV, null), paths); return null; } }, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE); } @Test public void testPassiveCellPermissions() throws Exception { final Configuration conf = TEST_UTIL.getConfiguration(); // store two sets of values, one store with a cell level ACL, and one without verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { try(Connection connection = ConnectionFactory.createConnection(conf); Table t = connection.getTable(TEST_TABLE.getTableName())) { Put p; // with ro ACL p = new Put(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1, ZERO); p.setACL(USER_NONE.getShortName(), new Permission(Action.READ)); t.put(p); // with rw ACL p = new Put(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2, ZERO); p.setACL(USER_NONE.getShortName(), new Permission(Action.READ, Action.WRITE)); t.put(p); // no ACL p = new Put(TEST_ROW) .addColumn(TEST_FAMILY, TEST_Q3, ZERO) .addColumn(TEST_FAMILY, TEST_Q4, ZERO); t.put(p); } return null; } }, USER_OWNER); // check that a scan over the test data returns the expected number of KVs final List<Cell> scanResults = Lists.newArrayList(); AccessTestAction scanAction = new AccessTestAction() { @Override public List<Cell> run() throws Exception { Scan scan = new Scan(); scan.setStartRow(TEST_ROW); scan.setStopRow(Bytes.add(TEST_ROW, new byte[]{ 0 } )); scan.addFamily(TEST_FAMILY); Connection connection = ConnectionFactory.createConnection(conf); Table t = connection.getTable(TEST_TABLE.getTableName()); try { ResultScanner scanner = t.getScanner(scan); Result result = null; do { result = scanner.next(); if (result != null) { scanResults.addAll(result.listCells()); } } while (result != null); } finally { t.close(); connection.close(); } return scanResults; } }; // owner will see all values scanResults.clear(); verifyAllowed(scanAction, USER_OWNER); assertEquals(4, scanResults.size()); // other user will also see 4 values // if cell filtering was active, we would only see 2 values scanResults.clear(); verifyAllowed(scanAction, USER_NONE); assertEquals(4, scanResults.size()); } }