Search in sources :

Example 16 with Action

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;
}
Also used : PrivilegedExceptionAction(java.security.PrivilegedExceptionAction) Action(org.apache.hadoop.hbase.security.access.Permission.Action) AccessDeniedException(org.apache.hadoop.hbase.security.AccessDeniedException) Set(java.util.Set) ImmutableSet(org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet) TreeSet(java.util.TreeSet) ByteRange(org.apache.hadoop.hbase.util.ByteRange) SimpleMutableByteRange(org.apache.hadoop.hbase.util.SimpleMutableByteRange) HashMap(java.util.HashMap) IOException(java.io.IOException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) SimpleMutableByteRange(org.apache.hadoop.hbase.util.SimpleMutableByteRange) RegionScanner(org.apache.hadoop.hbase.regionserver.RegionScanner) Get(org.apache.hadoop.hbase.client.Get) FilterList(org.apache.hadoop.hbase.filter.FilterList) ArrayList(java.util.ArrayList) List(java.util.List) Scan(org.apache.hadoop.hbase.client.Scan) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) Cell(org.apache.hadoop.hbase.Cell) ScannerContext(org.apache.hadoop.hbase.regionserver.ScannerContext)

Example 17 with Action

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());
}
Also used : AccessControlProtos(org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos) TableName(org.apache.hadoop.hbase.TableName) Action(org.apache.hadoop.hbase.security.access.Permission.Action) ByteString(org.apache.hbase.thirdparty.com.google.protobuf.ByteString)

Example 18 with Action

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();
        }
    }
}
Also used : PrivilegedAction(java.security.PrivilegedAction) Action(org.apache.hadoop.hbase.security.access.Permission.Action) User(org.apache.hadoop.hbase.security.User) Table(org.apache.hadoop.hbase.client.Table) AccessControlService(org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.AccessControlService) Connection(org.apache.hadoop.hbase.client.Connection) BlockingRpcChannel(org.apache.hbase.thirdparty.com.google.protobuf.BlockingRpcChannel) Test(org.junit.Test)

Example 19 with Action

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;
}
Also used : PrivilegedExceptionAction(java.security.PrivilegedExceptionAction) Action(org.apache.hadoop.hbase.security.access.Permission.Action)

Aggregations

Action (org.apache.hadoop.hbase.security.access.Permission.Action)19 PrivilegedExceptionAction (java.security.PrivilegedExceptionAction)17 AccessDeniedException (org.apache.hadoop.hbase.security.AccessDeniedException)13 PrivilegedAction (java.security.PrivilegedAction)7 User (org.apache.hadoop.hbase.security.User)4 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 TableName (org.apache.hadoop.hbase.TableName)2 Connection (org.apache.hadoop.hbase.client.Connection)2 Table (org.apache.hadoop.hbase.client.Table)2 BlockingRpcChannel (com.google.protobuf.BlockingRpcChannel)1 ServiceException (com.google.protobuf.ServiceException)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 TreeMap (java.util.TreeMap)1 TreeSet (java.util.TreeSet)1 Cell (org.apache.hadoop.hbase.Cell)1