/** * Authorizes that the current user has any of the given permissions for the * given table, column family and column qualifier. * @param tableName Table requested * @param family Column family requested * @param qualifier Column qualifier requested * @throws IOException if obtaining the current user fails * @throws AccessDeniedException if user has no authorization */ private void requirePermission(String request, TableName tableName, byte[] family, byte[] qualifier, Action... permissions) throws IOException { User user = getActiveUser(); AuthResult result = null; for (Action permission : permissions) { if (authManager.authorize(user, tableName, family, qualifier, permission)) { result = AuthResult.allow(request, "Table permission granted", user, permission, tableName, family, qualifier); break; } else { // rest of the world result = AuthResult.deny(request, "Insufficient permissions", user, permission, tableName, family, qualifier); } } logResult(result); if (authorizationEnabled && !result.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + result.toContextString()); } }
/** * Authorizes that the current user has any of the given permissions for the * given table, column family and column qualifier. * @param tableName Table requested * @param family Column family param * @param qualifier Column qualifier param * @throws IOException if obtaining the current user fails * @throws AccessDeniedException if user has no authorization */ private void requireTablePermission(String request, TableName tableName, byte[] family, byte[] qualifier, Action... permissions) throws IOException { User user = getActiveUser(); AuthResult result = null; for (Action permission : permissions) { if (authManager.authorize(user, tableName, null, null, permission)) { result = AuthResult.allow(request, "Table permission granted", user, permission, tableName, null, null); result.getParams().setFamily(family).setQualifier(qualifier); break; } else { // rest of the world result = AuthResult.deny(request, "Insufficient permissions", user, permission, tableName, family, qualifier); result.getParams().setFamily(family).setQualifier(qualifier); } } logResult(result); if (authorizationEnabled && !result.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + result.toContextString()); } }
/** * Checks that the user has the given global permission. The generated * audit log message will contain context information for the operation * being authorized, based on the given parameters. * @param perm Action being requested * @param tableName Affected table name. * @param familyMap Affected column families. */ private void requireGlobalPermission(String request, Action perm, TableName tableName, Map<byte[], ? extends Collection<byte[]>> familyMap) throws IOException { User user = getActiveUser(); AuthResult result = null; if (authManager.authorize(user, perm)) { result = AuthResult.allow(request, "Global check allowed", user, perm, tableName, familyMap); result.getParams().setTableName(tableName).setFamilies(familyMap); logResult(result); } else { result = AuthResult.deny(request, "Global check failed", user, perm, tableName, familyMap); result.getParams().setTableName(tableName).setFamilies(familyMap); logResult(result); if (authorizationEnabled) { throw new AccessDeniedException("Insufficient permissions for user '" + (user != null ? user.getShortName() : "null") +"' (global, action=" + perm.toString() + ")"); } } }
/** * Checks that the user has the given global permission. The generated * audit log message will contain context information for the operation * being authorized, based on the given parameters. * @param perm Action being requested * @param namespace */ private void requireGlobalPermission(String request, Action perm, String namespace) throws IOException { User user = getActiveUser(); AuthResult authResult = null; if (authManager.authorize(user, perm)) { authResult = AuthResult.allow(request, "Global check allowed", user, perm, null); authResult.getParams().setNamespace(namespace); logResult(authResult); } else { authResult = AuthResult.deny(request, "Global check failed", user, perm, null); authResult.getParams().setNamespace(namespace); logResult(authResult); if (authorizationEnabled) { throw new AccessDeniedException("Insufficient permissions for user '" + (user != null ? user.getShortName() : "null") +"' (global, action=" + perm.toString() + ")"); } } }
/** * Checks that the user has the given global or namespace permission. * @param namespace * @param permissions Actions being requested */ public void requireNamespacePermission(String request, String namespace, Action... permissions) throws IOException { User user = getActiveUser(); AuthResult result = null; for (Action permission : permissions) { if (authManager.authorize(user, namespace, permission)) { result = AuthResult.allow(request, "Namespace permission granted", user, permission, namespace); break; } else { // rest of the world result = AuthResult.deny(request, "Insufficient permissions", user, permission, namespace); } } logResult(result); if (authorizationEnabled && !result.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + result.toContextString()); } }
/** * Checks that the user has the given global or namespace permission. * @param namespace * @param permissions Actions being requested */ public void requireNamespacePermission(String request, String namespace, TableName tableName, Map<byte[], ? extends Collection<byte[]>> familyMap, Action... permissions) throws IOException { User user = getActiveUser(); AuthResult result = null; for (Action permission : permissions) { if (authManager.authorize(user, namespace, permission)) { result = AuthResult.allow(request, "Namespace permission granted", user, permission, namespace); result.getParams().setTableName(tableName).setFamilies(familyMap); break; } else { // rest of the world result = AuthResult.deny(request, "Insufficient permissions", user, permission, namespace); result.getParams().setTableName(tableName).setFamilies(familyMap); } } logResult(result); if (authorizationEnabled && !result.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + result.toContextString()); } }
@Override public void preTruncateTable(ObserverContext<MasterCoprocessorEnvironment> c, final TableName tableName) throws IOException { requirePermission("truncateTable", tableName, null, null, Action.ADMIN, Action.CREATE); final Configuration conf = c.getEnvironment().getConfiguration(); User.runAsLoginUser(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { List<UserPermission> acls = AccessControlLists.getUserTablePermissions(conf, tableName); if (acls != null) { tableAcls.put(tableName, acls); } return null; } }); }
@Override public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> c, TableName tableName, final HTableDescriptor htd) throws IOException { final Configuration conf = c.getEnvironment().getConfiguration(); // default the table owner to current user, if not specified. final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() : getActiveUser().getShortName(); User.runAsLoginUser(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { UserPermission userperm = new UserPermission(Bytes.toBytes(owner), htd.getTableName(), null, Action.values()); AccessControlLists.addUserPermission(conf, userperm); return null; } }); }
@Override public void postListProcedures( ObserverContext<MasterCoprocessorEnvironment> ctx, List<ProcedureInfo> procInfoList) throws IOException { if (procInfoList.isEmpty()) { return; } // Retains only those which passes authorization checks, as the checks weren't done as part // of preListProcedures. Iterator<ProcedureInfo> itr = procInfoList.iterator(); User user = getActiveUser(); while (itr.hasNext()) { ProcedureInfo procInfo = itr.next(); try { if (!ProcedureInfo.isProcedureOwner(procInfo, user)) { // If the user is not the procedure owner, then we should further probe whether // he can see the procedure. requirePermission("listProcedures", Action.ADMIN); } } catch (AccessDeniedException e) { itr.remove(); } } }
@Override public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException { RegionCoprocessorEnvironment env = e.getEnvironment(); final Region region = env.getRegion(); if (region == null) { LOG.error("NULL region from RegionCoprocessorEnvironment in preOpen()"); } else { HRegionInfo regionInfo = region.getRegionInfo(); if (regionInfo.getTable().isSystemTable()) { checkSystemOrSuperUser(); } else { requirePermission("preOpen", Action.ADMIN); } } }
@Override public boolean preCheckAndPutAfterRowLock(final ObserverContext<RegionCoprocessorEnvironment> c, final byte[] row, final byte[] family, final byte[] qualifier, final CompareFilter.CompareOp compareOp, final ByteArrayComparable comparator, final Put put, final boolean result) throws IOException { if (put.getAttribute(CHECK_COVERING_PERM) != null) { // We had failure with table, cf and q perm checks and now giving a chance for cell // perm check TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); Map<byte[], ? extends Collection<byte[]>> families = makeFamilyMap(family, qualifier); AuthResult authResult = null; if (checkCoveringPermission(OpType.CHECK_AND_PUT, c.getEnvironment(), row, families, HConstants.LATEST_TIMESTAMP, Action.READ)) { authResult = AuthResult.allow(OpType.CHECK_AND_PUT.toString(), "Covering cell set", getActiveUser(), Action.READ, table, families); } else { authResult = AuthResult.deny(OpType.CHECK_AND_PUT.toString(), "Covering cell set", getActiveUser(), Action.READ, table, families); } logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); } } return result; }
@Override public long preIncrementColumnValue(final ObserverContext<RegionCoprocessorEnvironment> c, final byte [] row, final byte [] family, final byte [] qualifier, final long amount, final boolean writeToWAL) throws IOException { // Require WRITE permission to the table, CF, and the KV to be replaced by the // incremented value RegionCoprocessorEnvironment env = c.getEnvironment(); Map<byte[],? extends Collection<byte[]>> families = makeFamilyMap(family, qualifier); User user = getActiveUser(); AuthResult authResult = permissionGranted(OpType.INCREMENT_COLUMN_VALUE, user, env, families, Action.WRITE); if (!authResult.isAllowed() && cellFeaturesEnabled && !compatibleEarlyTermination) { authResult.setAllowed(checkCoveringPermission(OpType.INCREMENT_COLUMN_VALUE, env, row, families, HConstants.LATEST_TIMESTAMP, Action.WRITE)); authResult.setReason("Covering cell set"); } logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); } return -1; }
@Override public Result preIncrementAfterRowLock(final ObserverContext<RegionCoprocessorEnvironment> c, final Increment increment) throws IOException { if (increment.getAttribute(CHECK_COVERING_PERM) != null) { // We had failure with table, cf and q perm checks and now giving a chance for cell // perm check TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); AuthResult authResult = null; if (checkCoveringPermission(OpType.INCREMENT, c.getEnvironment(), increment.getRow(), increment.getFamilyCellMap(), increment.getTimeRange().getMax(), Action.WRITE)) { authResult = AuthResult.allow(OpType.INCREMENT.toString(), "Covering cell set", getActiveUser(), Action.WRITE, table, increment.getFamilyCellMap()); } else { authResult = AuthResult.deny(OpType.INCREMENT.toString(), "Covering cell set", getActiveUser(), Action.WRITE, table, increment.getFamilyCellMap()); } logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); } } return null; }
@Test (timeout=180000) public void testGetNamespacePermission() throws Exception { String namespace = "testGetNamespacePermission"; NamespaceDescriptor desc = NamespaceDescriptor.create(namespace).build(); createNamespace(TEST_UTIL, desc); grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ); try { List<UserPermission> namespacePermissions = AccessControlClient.getUserPermissions( systemUserConnection, AccessControlLists.toNamespaceEntry(namespace)); assertTrue(namespacePermissions != null); assertTrue(namespacePermissions.size() == 1); } catch (Throwable thw) { throw new HBaseException(thw); } deleteNamespace(TEST_UTIL, namespace); }
@Override public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx, List<TableName> tableNamesList, List<HTableDescriptor> descriptors, String regex) throws IOException { // We are delegating the authorization check to postGetTableDescriptors as we don't have // any concrete set of table names when a regex is present or the full list is requested. if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) { // Otherwise, if the requestor has ADMIN or CREATE privs for all listed tables, the // request can be granted. MasterServices masterServices = ctx.getEnvironment().getMasterServices(); for (TableName tableName: tableNamesList) { // Skip checks for a table that does not exist if (masterServices.getTableDescriptors().get(tableName) == null) { continue; } requirePermission("getTableDescriptors", tableName, null, null, Action.ADMIN, Action.CREATE); } } }
@Override public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx, List<TableName> tableNamesList, List<HTableDescriptor> descriptors, String regex) throws IOException { // Skipping as checks in this case are already done by preGetTableDescriptors. if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) { return; } // Retains only those which passes authorization checks, as the checks weren't done as part // of preGetTableDescriptors. Iterator<HTableDescriptor> itr = descriptors.iterator(); while (itr.hasNext()) { HTableDescriptor htd = itr.next(); try { requirePermission("getTableDescriptors", htd.getTableName(), null, null, Action.ADMIN, Action.CREATE); } catch (AccessDeniedException e) { itr.remove(); } } }
@Test (timeout=180000) public void testNamespaceUserGrant() throws Exception { AccessTestAction getAction = new AccessTestAction() { @Override public Object run() throws Exception { try(Connection conn = ConnectionFactory.createConnection(conf); Table t = conn.getTable(TEST_TABLE);) { return t.get(new Get(TEST_ROW)); } } }; String namespace = TEST_TABLE.getNamespaceAsString(); // Grant namespace READ to USER_NONE, this should supersede any table permissions grantOnNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ); // Now USER_NONE should be able to read verifyAllowed(getAction, USER_NONE); // Revoke namespace READ to USER_NONE revokeFromNamespace(TEST_UTIL, USER_NONE.getShortName(), namespace, Permission.Action.READ); verifyDenied(getAction, USER_NONE); }
/** * Grant permissions globally to the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void grantGlobal(final HBaseTestingUtility util, final String user, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.grant(null, protocol, user, actions); } } return null; } }); }
/** * Revoke permissions globally from the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void revokeGlobal(final HBaseTestingUtility util, final String user, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.revoke(null, protocol, user, actions); } } return null; } }); }
/** * Grant permissions on a namespace to the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void grantOnNamespace(final HBaseTestingUtility util, final String user, final String namespace, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.grant(null, protocol, user, namespace, actions); } } return null; } }); }
/** * Grant permissions on a namespace to the given user using AccessControl Client. * Will wait until all active AccessController instances have updated their permissions caches * or will throw an exception upon timeout (10 seconds). */ public static void grantOnNamespaceUsingAccessControlClient(final HBaseTestingUtility util, final Connection connection, final String user, final String namespace, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try { AccessControlClient.grant(connection, namespace, user, actions); } catch (Throwable t) { t.printStackTrace(); } return null; } }); }
/** * Revoke permissions on a namespace from the given user using AccessControl Client. * Will wait until all active AccessController instances have updated their permissions caches * or will throw an exception upon timeout (10 seconds). */ public static void revokeFromNamespaceUsingAccessControlClient(final HBaseTestingUtility util, final Connection connection, final String user, final String namespace, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try { AccessControlClient.revoke(connection, namespace, user, actions); } catch (Throwable t) { t.printStackTrace(); } return null; } }); }
/** * Revoke permissions on a namespace from the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void revokeFromNamespace(final HBaseTestingUtility util, final String user, final String namespace, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.revoke(null, protocol, user, namespace, actions); } } return null; } }); }
/** * Grant permissions on a table to the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void grantOnTable(final HBaseTestingUtility util, final String user, final TableName table, final byte[] family, final byte[] qualifier, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.grant(null, protocol, user, table, family, qualifier, actions); } } return null; } }); }
/** * Grant permissions on a table to the given user using AccessControlClient. Will wait until all * active AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void grantOnTableUsingAccessControlClient(final HBaseTestingUtility util, final Connection connection, final String user, final TableName table, final byte[] family, final byte[] qualifier, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try { AccessControlClient.grant(connection, table, user, family, qualifier, actions); } catch (Throwable t) { t.printStackTrace(); } return null; } }); }
/** * Grant global permissions to the given user using AccessControlClient. Will wait until all * active AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void grantGlobalUsingAccessControlClient(final HBaseTestingUtility util, final Connection connection, final String user, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try { AccessControlClient.grant(connection, user, actions); } catch (Throwable t) { t.printStackTrace(); } return null; } }); }
/** * Revoke permissions on a table from the given user. Will wait until all active * AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void revokeFromTable(final HBaseTestingUtility util, final String user, final TableName table, final byte[] family, final byte[] qualifier, final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); ProtobufUtil.revoke(null, protocol, user, table, family, qualifier, actions); } } return null; } }); }
/** * Revoke global permissions from the given user using AccessControlClient. Will wait until * all active AccessController instances have updated their permissions caches or will * throw an exception upon timeout (10 seconds). */ public static void revokeGlobalUsingAccessControlClient(final HBaseTestingUtility util, final Connection connection, final String user,final Permission.Action... actions) throws Exception { SecureTestUtil.updateACLs(util, new Callable<Void>() { @Override public Void call() throws Exception { try { AccessControlClient.revoke(connection, user, actions); } catch (Throwable t) { t.printStackTrace(); } return null; } }); }
public static void checkGlobalPerms(HBaseTestingUtility testUtil, Permission.Action... actions) throws IOException { Permission[] perms = new Permission[actions.length]; for (int i = 0; i < actions.length; i++) { perms[i] = new Permission(actions[i]); } CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder(); for (Action a : actions) { request.addPermission(AccessControlProtos.Permission.newBuilder() .setType(AccessControlProtos.Permission.Type.Global) .setGlobalPermission( AccessControlProtos.GlobalPermission.newBuilder() .addAction(ProtobufUtil.toPermissionAction(a)).build())); } try(Connection conn = ConnectionFactory.createConnection(testUtil.getConfiguration()); Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { BlockingRpcChannel channel = acl.coprocessorService(new byte[0]); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(channel); try { protocol.checkPermissions(null, request.build()); } catch (ServiceException se) { ProtobufUtil.toIOException(se); } } }
@Test (timeout=180000) public void testCreateTableWithGroupPermissions() throws Exception { grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE); try { AccessTestAction createAction = new AccessTestAction() { @Override public Object run() throws Exception { HTableDescriptor desc = new HTableDescriptor(TEST_TABLE.getTableName()); desc.addFamily(new HColumnDescriptor(TEST_FAMILY)); try (Connection connection = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) { try (Admin admin = connection.getAdmin()) { admin.createTable(desc); } } return null; } }; verifyAllowed(createAction, TESTGROUP1_USER1); verifyDenied(createAction, TESTGROUP2_USER1); } finally { revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE); } }
/** * Check the current user for authorization to perform a specific action * against the given set of row data. * @param opType the operation type * @param user the user * @param e the coprocessor environment * @param families the map of column families to qualifiers present in * the request * @param actions the desired actions * @return an authorization result */ AuthResult permissionGranted(OpType opType, User user, RegionCoprocessorEnvironment e, Map<byte [], ? extends Collection<?>> families, Action... actions) { AuthResult result = null; for (Action action: actions) { result = permissionGranted(opType.toString(), user, action, e, families); if (!result.isAllowed()) { return result; } } return result; }
/** * Authorizes that the current user has any of the given permissions to access the table. * * @param tableName Table requested * @param permissions Actions being requested * @throws IOException if obtaining the current user fails * @throws AccessDeniedException if user has no authorization */ private void requireAccess(String request, TableName tableName, Action... permissions) throws IOException { User user = getActiveUser(); AuthResult result = null; for (Action permission : permissions) { if (authManager.hasAccess(user, tableName, permission)) { result = AuthResult.allow(request, "Table permission granted", user, permission, tableName, null, null); break; } else { // rest of the world result = AuthResult.deny(request, "Insufficient permissions", user, permission, tableName, null, null); } } logResult(result); if (authorizationEnabled && !result.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + result.toContextString()); } }
/** * Returns <code>true</code> if the current user is allowed the given action * over at least one of the column qualifiers in the given column families. */ private boolean hasFamilyQualifierPermission(User user, Action perm, RegionCoprocessorEnvironment env, Map<byte[], ? extends Collection<byte[]>> familyMap) throws IOException { HRegionInfo hri = env.getRegion().getRegionInfo(); TableName tableName = hri.getTable(); if (user == null) { return false; } if (familyMap != null && familyMap.size() > 0) { // at least one family must be allowed for (Map.Entry<byte[], ? extends Collection<byte[]>> family : familyMap.entrySet()) { if (family.getValue() != null && !family.getValue().isEmpty()) { for (byte[] qualifier : family.getValue()) { if (authManager.matchPermission(user, tableName, family.getKey(), qualifier, perm)) { return true; } } } else { if (authManager.matchPermission(user, tableName, family.getKey(), perm)) { return true; } } } } else if (LOG.isDebugEnabled()) { LOG.debug("Empty family map passed for permission check"); } return false; }
@Override public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> c, HTableDescriptor desc, HRegionInfo[] regions) throws IOException { Set<byte[]> families = desc.getFamiliesKeys(); Map<byte[], Set<byte[]>> familyMap = new TreeMap<byte[], Set<byte[]>>(Bytes.BYTES_COMPARATOR); for (byte[] family: families) { familyMap.put(family, null); } requireNamespacePermission("createTable", desc.getTableName().getNamespaceAsString(), desc.getTableName(), familyMap, Action.CREATE); }
@Override public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> c, TableName tableName) throws IOException { if (Bytes.equals(tableName.getName(), AccessControlLists.ACL_GLOBAL_NAME)) { // We have to unconditionally disallow disable of the ACL table when we are installed, // even if not enforcing authorizations. We are still allowing grants and revocations, // checking permissions and logging audit messages, etc. If the ACL table is not // available we will fail random actions all over the place. throw new AccessDeniedException("Not allowed to disable " + AccessControlLists.ACL_TABLE_NAME + " table with AccessController installed"); } requirePermission("disableTable", tableName, null, null, Action.ADMIN, Action.CREATE); }
@Override public void preAbortProcedure( ObserverContext<MasterCoprocessorEnvironment> ctx, final ProcedureExecutor<MasterProcedureEnv> procEnv, final long procId) throws IOException { if (!procEnv.isProcedureOwner(procId, getActiveUser())) { // If the user is not the procedure owner, then we should further probe whether // he can abort the procedure. requirePermission("abortProcedure", Action.ADMIN); } }
@Override public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx, final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor) throws IOException { requirePermission("snapshot", hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN); }
@Override public void preListSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx, final SnapshotDescription snapshot) throws IOException { if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) { // list it, if user is the owner of snapshot } else { requirePermission("listSnapshot", Action.ADMIN); } }
@Override public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx, final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor) throws IOException { if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) { requirePermission("restoreSnapshot", hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN); } else { requirePermission("restore", Action.ADMIN); } }
@Override public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx, final SnapshotDescription snapshot) throws IOException { if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) { // Snapshot owner is allowed to delete the snapshot // TODO: We are not logging this for audit } else { requirePermission("deleteSnapshot", Action.ADMIN); } }