HBASE-13241 Add tests for group level grants
This commit is contained in:
parent
64589abe99
commit
2bf904f216
|
@ -17,20 +17,26 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.security.access;
|
package org.apache.hadoop.hbase.security.access;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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.conf.Configuration;
|
||||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||||
|
import org.apache.hadoop.hbase.NamespaceDescriptor;
|
||||||
|
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.Admin;
|
||||||
import org.apache.hadoop.hbase.client.Connection;
|
import org.apache.hadoop.hbase.client.Connection;
|
||||||
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
||||||
import org.apache.hadoop.hbase.client.HTable;
|
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
import org.apache.hadoop.hbase.client.ResultScanner;
|
import org.apache.hadoop.hbase.client.ResultScanner;
|
||||||
|
@ -42,7 +48,9 @@ import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
import org.apache.hadoop.hbase.testclassification.SecurityTests;
|
import org.apache.hadoop.hbase.testclassification.SecurityTests;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
import org.apache.hadoop.hbase.util.TestTableName;
|
import org.apache.hadoop.hbase.util.TestTableName;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -50,6 +58,7 @@ import org.junit.experimental.categories.Category;
|
||||||
|
|
||||||
@Category({SecurityTests.class, LargeTests.class})
|
@Category({SecurityTests.class, LargeTests.class})
|
||||||
public class TestAccessController2 extends SecureTestUtil {
|
public class TestAccessController2 extends SecureTestUtil {
|
||||||
|
private static final Log LOG = LogFactory.getLog(TestAccessController2.class);
|
||||||
|
|
||||||
private static final byte[] TEST_ROW = Bytes.toBytes("test");
|
private static final byte[] TEST_ROW = Bytes.toBytes("test");
|
||||||
private static final byte[] TEST_FAMILY = Bytes.toBytes("f");
|
private static final byte[] TEST_FAMILY = Bytes.toBytes("f");
|
||||||
|
@ -59,7 +68,29 @@ public class TestAccessController2 extends SecureTestUtil {
|
||||||
private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
private static Configuration conf;
|
private static Configuration conf;
|
||||||
|
|
||||||
@Rule public TestTableName TEST_TABLE = new TestTableName();
|
private static Connection connection;
|
||||||
|
|
||||||
|
private final static byte[] Q1 = Bytes.toBytes("q1");
|
||||||
|
private final static byte[] value1 = Bytes.toBytes("value1");
|
||||||
|
|
||||||
|
private static byte[] TEST_FAMILY_2 = Bytes.toBytes("f2");
|
||||||
|
private static byte[] TEST_ROW_2 = Bytes.toBytes("r2");
|
||||||
|
private final static byte[] Q2 = Bytes.toBytes("q2");
|
||||||
|
private final static byte[] value2 = Bytes.toBytes("value2");
|
||||||
|
|
||||||
|
private static byte[] TEST_ROW_3 = Bytes.toBytes("r3");
|
||||||
|
|
||||||
|
private static final String TESTGROUP_1 = "testgroup_1";
|
||||||
|
private static final String TESTGROUP_2 = "testgroup_2";
|
||||||
|
|
||||||
|
private static User TESTGROUP1_USER1;
|
||||||
|
private static User TESTGROUP2_USER1;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestTableName TEST_TABLE = new TestTableName();
|
||||||
|
private String namespace = "testNamespace";
|
||||||
|
private String tname = namespace + ":testtable1";
|
||||||
|
private TableName tableName = TableName.valueOf(tname);
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setupBeforeClass() throws Exception {
|
public static void setupBeforeClass() throws Exception {
|
||||||
|
@ -70,14 +101,72 @@ public class TestAccessController2 extends SecureTestUtil {
|
||||||
verifyConfiguration(conf);
|
verifyConfiguration(conf);
|
||||||
TEST_UTIL.startMiniCluster();
|
TEST_UTIL.startMiniCluster();
|
||||||
// Wait for the ACL table to become available
|
// Wait for the ACL table to become available
|
||||||
TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME);
|
TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
|
||||||
|
|
||||||
|
TESTGROUP1_USER1 =
|
||||||
|
User.createUserForTesting(conf, "testgroup1_user1", new String[] { TESTGROUP_1 });
|
||||||
|
TESTGROUP2_USER1 =
|
||||||
|
User.createUserForTesting(conf, "testgroup2_user2", new String[] { TESTGROUP_2 });
|
||||||
|
|
||||||
|
connection = ConnectionFactory.createConnection(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
TEST_UTIL.getHBaseAdmin().createNamespace(NamespaceDescriptor.create(namespace).build());
|
||||||
|
try (Table table =
|
||||||
|
TEST_UTIL.createTable(tableName,
|
||||||
|
new String[] { Bytes.toString(TEST_FAMILY), Bytes.toString(TEST_FAMILY_2) })) {
|
||||||
|
TEST_UTIL.waitTableEnabled(tableName);
|
||||||
|
|
||||||
|
List<Put> puts = new ArrayList<Put>(5);
|
||||||
|
Put put_1 = new Put(TEST_ROW);
|
||||||
|
put_1.addColumn(TEST_FAMILY, Q1, value1);
|
||||||
|
|
||||||
|
Put put_2 = new Put(TEST_ROW_2);
|
||||||
|
put_2.addColumn(TEST_FAMILY, Q2, value2);
|
||||||
|
|
||||||
|
Put put_3 = new Put(TEST_ROW_3);
|
||||||
|
put_3.addColumn(TEST_FAMILY_2, Q1, value1);
|
||||||
|
|
||||||
|
puts.add(put_1);
|
||||||
|
puts.add(put_2);
|
||||||
|
puts.add(put_3);
|
||||||
|
|
||||||
|
table.put(puts);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(1, AccessControlLists.getTablePermissions(conf, tableName).size());
|
||||||
|
try {
|
||||||
|
assertEquals(1, AccessControlClient.getUserPermissions(connection, tableName.toString())
|
||||||
|
.size());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.error("Error during call of AccessControlClient.getUserPermissions. ", e);
|
||||||
|
}
|
||||||
|
// setupOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void tearDownAfterClass() throws Exception {
|
public static void tearDownAfterClass() throws Exception {
|
||||||
|
connection.close();
|
||||||
TEST_UTIL.shutdownMiniCluster();
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
// Clean the _acl_ table
|
||||||
|
try {
|
||||||
|
deleteTable(TEST_UTIL, tableName);
|
||||||
|
} catch (TableNotFoundException ex) {
|
||||||
|
// Test deleted the table, no problem
|
||||||
|
LOG.info("Test deleted table " + tableName);
|
||||||
|
}
|
||||||
|
TEST_UTIL.getHBaseAdmin().deleteNamespace(namespace);
|
||||||
|
// Verify all table/namespace permissions are erased
|
||||||
|
assertEquals(0, AccessControlLists.getTablePermissions(conf, tableName).size());
|
||||||
|
assertEquals(0, AccessControlLists.getNamespacePermissions(conf, namespace).size());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateWithCorrectOwner() throws Exception {
|
public void testCreateWithCorrectOwner() throws Exception {
|
||||||
// Create a test user
|
// Create a test user
|
||||||
|
@ -213,4 +302,138 @@ public class TestAccessController2 extends SecureTestUtil {
|
||||||
verifyAllowed(scanAction, superUser, globalRead);
|
verifyAllowed(scanAction, superUser, globalRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test table scan operation at table, column family and column qualifier level.
|
||||||
|
*/
|
||||||
|
@Test(timeout = 300000)
|
||||||
|
public void testPostGrantAndRevokeScanAction() throws Exception {
|
||||||
|
AccessTestAction scanTableActionForGroupWithTableLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
Result[] next1 = scanner1.next(5);
|
||||||
|
assertTrue("User having table level access should be able to scan all "
|
||||||
|
+ "the data in the table.", next1.length == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessTestAction scanTableActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
Result[] next1 = scanner1.next(5);
|
||||||
|
assertTrue("User having column family level access should be able to scan all "
|
||||||
|
+ "the data belonging to that family.", next1.length == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessTestAction scanFamilyActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
s1.addFamily(TEST_FAMILY_2);
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessTestAction scanTableActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
Result[] next1 = scanner1.next(5);
|
||||||
|
assertTrue("User having column qualifier level access should be able to scan "
|
||||||
|
+ "that column family qualifier data.", next1.length == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessTestAction scanFamilyActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
s1.addFamily(TEST_FAMILY_2);
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessTestAction scanQualifierActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
try (Connection connection = ConnectionFactory.createConnection(conf);
|
||||||
|
Table table = connection.getTable(tableName);) {
|
||||||
|
Scan s1 = new Scan();
|
||||||
|
s1.addColumn(TEST_FAMILY, Q2);
|
||||||
|
try (ResultScanner scanner1 = table.getScanner(s1);) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify user from a group which has table level access can read all the data and group which
|
||||||
|
// has no access can't read any data.
|
||||||
|
grantOnTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, null, null, Permission.Action.READ);
|
||||||
|
verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithTableLevelAccess);
|
||||||
|
|
||||||
|
// Verify user from a group whose table level access has been revoked can't read any data.
|
||||||
|
revokeFromTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, null, null);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
|
||||||
|
|
||||||
|
// Verify user from a group which has column family level access can read all the data
|
||||||
|
// belonging to that family and group which has no access can't read any data.
|
||||||
|
grantOnTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, TEST_FAMILY, null,
|
||||||
|
Permission.Action.READ);
|
||||||
|
verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithFamilyLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
|
||||||
|
|
||||||
|
// Verify user from a group whose column family level access has been revoked can't read any
|
||||||
|
// data from that family.
|
||||||
|
revokeFromTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, TEST_FAMILY, null);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
|
||||||
|
|
||||||
|
// Verify user from a group which has column qualifier level access can read data that has this
|
||||||
|
// family and qualifier, and group which has no access can't read any data.
|
||||||
|
grantOnTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, TEST_FAMILY, Q1, Permission.Action.READ);
|
||||||
|
verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithQualifierLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
|
||||||
|
verifyDenied(TESTGROUP2_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
|
||||||
|
|
||||||
|
// Verify user from a group whose column qualifier level access has been revoked can't read the
|
||||||
|
// data having this column family and qualifier.
|
||||||
|
revokeFromTable(TEST_UTIL, '@' + TESTGROUP_1, tableName, TEST_FAMILY, Q1);
|
||||||
|
verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue