use of org.apache.hadoop.hbase.security.access.Permission.Action in project hbase by apache.
the class AccessController method checkCoveringPermission.
/**
* Determine if cell ACLs covered by the operation grant access. This is expensive.
* @return false if cell ACLs failed to grant access, true otherwise
* @throws IOException
*/
private boolean checkCoveringPermission(User user, OpType request, RegionCoprocessorEnvironment e, byte[] row, Map<byte[], ? extends Collection<?>> familyMap, long opTs, Action... actions) throws IOException {
if (!cellFeaturesEnabled) {
return false;
}
long cellGrants = 0;
long latestCellTs = 0;
Get get = new Get(row);
// Only in case of Put/Delete op, consider TS within cell (if set for individual cells).
// When every cell, within a Mutation, can be linked with diff TS we can not rely on only one
// version. We have to get every cell version and check its TS against the TS asked for in
// Mutation and skip those Cells which is outside this Mutation TS.In case of Put, we have to
// consider only one such passing cell. In case of Delete we have to consider all the cell
// versions under this passing version. When Delete Mutation contains columns which are a
// version delete just consider only one version for those column cells.
boolean considerCellTs = (request == OpType.PUT || request == OpType.DELETE);
if (considerCellTs) {
get.readAllVersions();
} else {
get.readVersions(1);
}
boolean diffCellTsFromOpTs = false;
for (Map.Entry<byte[], ? extends Collection<?>> entry : familyMap.entrySet()) {
byte[] col = entry.getKey();
// maps so we would not need to do this
if (entry.getValue() instanceof Set) {
Set<byte[]> set = (Set<byte[]>) entry.getValue();
if (set == null || set.isEmpty()) {
get.addFamily(col);
} else {
for (byte[] qual : set) {
get.addColumn(col, qual);
}
}
} else if (entry.getValue() instanceof List) {
List<Cell> list = (List<Cell>) entry.getValue();
if (list == null || list.isEmpty()) {
get.addFamily(col);
} else {
// In case of family delete, a Cell will be added into the list with Qualifier as null.
for (Cell cell : list) {
if (cell.getQualifierLength() == 0 && (cell.getTypeByte() == Type.DeleteFamily.getCode() || cell.getTypeByte() == Type.DeleteFamilyVersion.getCode())) {
get.addFamily(col);
} else {
get.addColumn(col, CellUtil.cloneQualifier(cell));
}
if (considerCellTs) {
long cellTs = cell.getTimestamp();
latestCellTs = Math.max(latestCellTs, cellTs);
diffCellTsFromOpTs = diffCellTsFromOpTs || (opTs != cellTs);
}
}
}
} else if (entry.getValue() == null) {
get.addFamily(col);
} else {
throw new RuntimeException("Unhandled collection type " + entry.getValue().getClass().getName());
}
}
// We want to avoid looking into the future. So, if the cells of the
// operation specify a timestamp, or the operation itself specifies a
// timestamp, then we use the maximum ts found. Otherwise, we bound
// the Get to the current server time. We add 1 to the timerange since
// the upper bound of a timerange is exclusive yet we need to examine
// any cells found there inclusively.
long latestTs = Math.max(opTs, latestCellTs);
if (latestTs == 0 || latestTs == HConstants.LATEST_TIMESTAMP) {
latestTs = EnvironmentEdgeManager.currentTime();
}
get.setTimeRange(0, latestTs + 1);
// case with Put. There no need to get all versions but get latest version only.
if (!diffCellTsFromOpTs && request == OpType.PUT) {
get.readVersions(1);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Scanning for cells with " + get);
}
// This Map is identical to familyMap. The key is a BR rather than byte[].
// It will be easy to do gets over this new Map as we can create get keys over the Cell cf by
// new SimpleByteRange(cell.familyArray, cell.familyOffset, cell.familyLen)
Map<ByteRange, List<Cell>> familyMap1 = new HashMap<>();
for (Entry<byte[], ? extends Collection<?>> entry : familyMap.entrySet()) {
if (entry.getValue() instanceof List) {
familyMap1.put(new SimpleMutableByteRange(entry.getKey()), (List<Cell>) entry.getValue());
}
}
RegionScanner scanner = getRegion(e).getScanner(new Scan(get));
List<Cell> cells = Lists.newArrayList();
Cell prevCell = null;
ByteRange curFam = new SimpleMutableByteRange();
boolean curColAllVersions = (request == OpType.DELETE);
long curColCheckTs = opTs;
boolean foundColumn = false;
try {
boolean more = false;
ScannerContext scannerContext = ScannerContext.newBuilder().setBatchLimit(1).build();
do {
cells.clear();
// scan with limit as 1 to hold down memory use on wide rows
more = scanner.next(cells, scannerContext);
for (Cell cell : cells) {
if (LOG.isTraceEnabled()) {
LOG.trace("Found cell " + cell);
}
boolean colChange = prevCell == null || !CellUtil.matchingColumn(prevCell, cell);
if (colChange)
foundColumn = false;
prevCell = cell;
if (!curColAllVersions && foundColumn) {
continue;
}
if (colChange && considerCellTs) {
curFam.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
List<Cell> cols = familyMap1.get(curFam);
for (Cell col : cols) {
// why the below (col.getQualifierLength() == 0) check.
if ((col.getQualifierLength() == 0 && request == OpType.DELETE) || CellUtil.matchingQualifier(cell, col)) {
byte type = col.getTypeByte();
if (considerCellTs) {
curColCheckTs = col.getTimestamp();
}
// For a Delete op we pass allVersions as true. When a Delete Mutation contains
// a version delete for a column no need to check all the covering cells within
// that column. Check all versions when Type is DeleteColumn or DeleteFamily
// One version delete types are Delete/DeleteFamilyVersion
curColAllVersions = (KeyValue.Type.DeleteColumn.getCode() == type) || (KeyValue.Type.DeleteFamily.getCode() == type);
break;
}
}
}
if (cell.getTimestamp() > curColCheckTs) {
// Just ignore this cell. This is not a covering cell.
continue;
}
foundColumn = true;
for (Action action : actions) {
// Are there permissions for this user for the cell?
if (!getAuthManager().authorizeCell(user, getTableName(e), cell, action)) {
// We can stop if the cell ACL denies access
return false;
}
}
cellGrants++;
}
} while (more);
} catch (AccessDeniedException ex) {
throw ex;
} catch (IOException ex) {
LOG.error("Exception while getting cells to calculate covering permission", ex);
} finally {
scanner.close();
}
// after no table or CF grants are found.
return cellGrants > 0;
}
use of org.apache.hadoop.hbase.security.access.Permission.Action in project hbase by apache.
the class ShadedAccessControlUtil method toPermission.
/**
* Converts a Permission shaded proto to a client TablePermission object.
* @param proto the protobuf Permission
* @return the converted TablePermission
*/
public static Permission toPermission(AccessControlProtos.Permission proto) {
if (proto.getType() == AccessControlProtos.Permission.Type.Global) {
AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
Action[] actions = toPermissionActions(perm.getActionList());
return Permission.newBuilder().withActions(actions).build();
}
if (proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
Action[] actions = toPermissionActions(perm.getActionList());
if (!proto.hasNamespacePermission()) {
throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
}
String ns = perm.getNamespaceName().toStringUtf8();
return Permission.newBuilder(ns).withActions(actions).build();
}
if (proto.getType() == AccessControlProtos.Permission.Type.Table) {
AccessControlProtos.TablePermission perm = proto.getTablePermission();
Action[] actions = toPermissionActions(perm.getActionList());
byte[] qualifier = null;
byte[] family = null;
if (!perm.hasTableName()) {
throw new IllegalStateException("TableName cannot be empty");
}
TableName table = toTableName(perm.getTableName());
if (perm.hasFamily())
family = perm.getFamily().toByteArray();
if (perm.hasQualifier())
qualifier = perm.getQualifier().toByteArray();
return Permission.newBuilder(table).withFamily(family).withQualifier(qualifier).withActions(actions).build();
}
throw new IllegalStateException("Unrecognize Perm Type: " + proto.getType());
}
use of org.apache.hadoop.hbase.security.access.Permission.Action in project hbase by apache.
the class TestAccessController method testHasPermission.
@Test
public void testHasPermission() throws Throwable {
Connection conn = null;
try {
conn = ConnectionFactory.createConnection(conf);
// Create user and set namespace ACL
User user1 = User.createUserForTesting(conf, "testHasPermissionUser1", new String[0]);
// Grant namespace permission
grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conn, user1.getShortName(), NamespaceDescriptor.DEFAULT_NAMESPACE.getName(), Permission.Action.ADMIN, Permission.Action.CREATE, Permission.Action.READ);
// Create user and set table ACL
User user2 = User.createUserForTesting(conf, "testHasPermissionUser2", new String[0]);
// Grant namespace permission
grantOnTableUsingAccessControlClient(TEST_UTIL, conn, user2.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, Permission.Action.READ, Permission.Action.WRITE);
// Verify action privilege
AccessTestAction hasPermissionActionCP = new AccessTestAction() {
@Override
public Object run() throws Exception {
try (Connection conn = ConnectionFactory.createConnection(conf);
Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) {
BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName());
AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service);
Permission.Action[] actions = { Permission.Action.READ, Permission.Action.WRITE };
AccessControlUtil.hasPermission(null, protocol, TEST_TABLE, TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, "dummy", actions);
}
return null;
}
};
AccessTestAction hasPermissionAction = new AccessTestAction() {
@Override
public Object run() throws Exception {
try (Connection conn = ConnectionFactory.createConnection(conf)) {
Permission.Action[] actions = { Permission.Action.READ, Permission.Action.WRITE };
conn.getAdmin().hasUserPermissions("dummy", Arrays.asList(Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(HConstants.EMPTY_BYTE_ARRAY).withActions(actions).build()));
}
return null;
}
};
verifyAllowed(hasPermissionActionCP, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER, USER_ADMIN_CF, user1);
verifyDenied(hasPermissionActionCP, USER_CREATE, USER_RW, USER_RO, USER_NONE, user2);
verifyAllowed(hasPermissionAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN, USER_OWNER, USER_ADMIN_CF, user1);
verifyDenied(hasPermissionAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, user2);
// Check for global user
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN.getShortName(), Permission.Action.READ, Permission.Action.WRITE, Permission.Action.CREATE, Permission.Action.ADMIN));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN.getShortName(), Permission.Action.READ, Permission.Action.WRITE, Permission.Action.CREATE, Permission.Action.ADMIN, Permission.Action.EXEC));
// Check for namespace access user
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, user1.getShortName(), Permission.Action.ADMIN, Permission.Action.CREATE));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, user1.getShortName(), Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.EXEC));
// Check for table owner
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_OWNER.getShortName(), Permission.Action.READ, Permission.Action.WRITE, Permission.Action.EXEC, Permission.Action.CREATE, Permission.Action.ADMIN));
// Check for table user
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_CREATE.getShortName(), Permission.Action.READ, Permission.Action.WRITE));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_RO.getShortName(), Permission.Action.READ, Permission.Action.WRITE));
// Check for family access user
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, USER_RO.getShortName(), Permission.Action.READ));
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, USER_RW.getShortName(), Permission.Action.READ, Permission.Action.WRITE));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(), Permission.Action.ADMIN, Permission.Action.CREATE));
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(), Permission.Action.ADMIN, Permission.Action.CREATE));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, HConstants.EMPTY_BYTE_ARRAY, USER_ADMIN_CF.getShortName(), Permission.Action.READ));
// Check for qualifier access user
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, TEST_QUALIFIER, user2.getShortName(), Permission.Action.READ, Permission.Action.WRITE));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), TEST_FAMILY, TEST_QUALIFIER, user2.getShortName(), Permission.Action.EXEC, Permission.Action.READ));
assertFalse(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, TEST_QUALIFIER, USER_RW.getShortName(), Permission.Action.WRITE, Permission.Action.READ));
// exception scenarios
try {
// test case with table name as null
assertTrue(AccessControlClient.hasPermission(conn, null, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, null, Permission.Action.READ));
fail("this should have thrown IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// expected
}
try {
// test case with username as null
assertTrue(AccessControlClient.hasPermission(conn, TEST_TABLE.getNameAsString(), HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, null, Permission.Action.READ));
fail("this should have thrown IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// expected
}
revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conn, user1.getShortName(), NamespaceDescriptor.DEFAULT_NAMESPACE.getName(), Permission.Action.ADMIN, Permission.Action.CREATE, Permission.Action.READ);
revokeFromTableUsingAccessControlClient(TEST_UTIL, conn, user2.getShortName(), TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, Permission.Action.READ, Permission.Action.WRITE);
} finally {
if (conn != null) {
conn.close();
}
}
}
use of org.apache.hadoop.hbase.security.access.Permission.Action in project ranger by apache.
the class RangerHBasePlugin method getUserPermissions.
private List<UserPermission> getUserPermissions(RangerResourceACLs rangerResourceACLs, String resource, boolean isNamespace) {
List<UserPermission> userPermissions = new ArrayList<UserPermission>();
Action[] hbaseActions = Action.values();
List<String> hbaseActionsList = new ArrayList<String>();
for (Action action : hbaseActions) {
hbaseActionsList.add(action.name());
}
addPermission(rangerResourceACLs.getUserACLs(), isNamespace, hbaseActionsList, userPermissions, resource, false);
addPermission(rangerResourceACLs.getGroupACLs(), isNamespace, hbaseActionsList, userPermissions, resource, true);
return userPermissions;
}
Aggregations