HBASE-22117 Move hasPermission/checkPermissions from region server to master

Signed-off-by: Guanghao Zhang <zghao@apache.org>
This commit is contained in:
meiyi 2019-03-28 18:50:08 +08:00 committed by Guanghao Zhang
parent 89ce5d17e4
commit d32f924ef4
22 changed files with 583 additions and 315 deletions

View File

@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
@ -2107,4 +2108,24 @@ public interface Admin extends Abortable, Closeable {
*/
List<UserPermission> getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest)
throws IOException;
/**
* Check if the user has specific permissions
* @param userName the user name
* @param permissions the specific permission list
* @return True if user has the specific permissions
* @throws IOException if a remote or network exception occurs
*/
List<Boolean> hasUserPermissions(String userName, List<Permission> permissions)
throws IOException;
/**
* Check if call user has specific permissions
* @param permissions the specific permission list
* @return True if user has the specific permissions
* @throws IOException if a remote or network exception occurs
*/
default List<Boolean> hasUserPermissions(List<Permission> permissions) throws IOException {
return hasUserPermissions(null, permissions);
}
}

View File

@ -47,6 +47,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.yetus.audience.InterfaceAudience;
@ -1457,4 +1458,22 @@ public interface AsyncAdmin {
*/
CompletableFuture<List<UserPermission>>
getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest);
/**
* Check if the user has specific permissions
* @param userName the user name
* @param permissions the specific permission list
* @return True if user has the specific permissions
*/
CompletableFuture<List<Boolean>> hasUserPermissions(String userName,
List<Permission> permissions);
/**
* Check if call user has specific permissions
* @param permissions the specific permission list
* @return True if user has the specific permissions
*/
default CompletableFuture<List<Boolean>> hasUserPermissions(List<Permission> permissions) {
return hasUserPermissions(null, permissions);
}
}

View File

@ -43,6 +43,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.util.FutureUtils;
import org.apache.yetus.audience.InterfaceAudience;
@ -814,4 +815,10 @@ class AsyncHBaseAdmin implements AsyncAdmin {
getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) {
return wrap(rawAdmin.getUserPermissions(getUserPermissionsRequest));
}
@Override
public CompletableFuture<List<Boolean>> hasUserPermissions(String userName,
List<Permission> permissions) {
return wrap(rawAdmin.hasUserPermissions(userName, permissions));
}
}

View File

@ -95,6 +95,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService.BlockingInterface;
@ -1803,6 +1805,12 @@ class ConnectionImplementation implements ClusterConnection, Closeable {
GetUserPermissionsRequest request) throws ServiceException {
return stub.getUserPermissions(controller, request);
}
@Override
public HasUserPermissionsResponse hasUserPermissions(RpcController controller,
HasUserPermissionsRequest request) throws ServiceException {
return stub.hasUserPermissions(controller, request);
}
};
}

View File

@ -86,6 +86,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
@ -113,6 +114,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.AdminService;
@ -3853,6 +3855,21 @@ public class HBaseAdmin implements Admin {
});
}
@Override
public List<Boolean> hasUserPermissions(String userName, List<Permission> permissions)
throws IOException {
return executeCallable(
new MasterCallable<List<Boolean>>(getConnection(), getRpcControllerFactory()) {
@Override
protected List<Boolean> rpcCall() throws Exception {
HasUserPermissionsRequest request =
ShadedAccessControlUtil.buildHasUserPermissionsRequest(userName, permissions);
return this.master.hasUserPermissions(getRpcController(), request)
.getHasUserPermissionList();
}
});
}
@Override
public void close() {
}

View File

@ -87,6 +87,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
@ -112,6 +113,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.AdminService;
@ -3824,4 +3827,16 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
.collect(Collectors.toList())))
.call();
}
@Override
public CompletableFuture<List<Boolean>> hasUserPermissions(String userName,
List<Permission> permissions) {
return this.<List<Boolean>> newMasterCaller()
.action((controller, stub) -> this
.<HasUserPermissionsRequest, HasUserPermissionsResponse, List<Boolean>> call(controller,
stub, ShadedAccessControlUtil.buildHasUserPermissionsRequest(userName, permissions),
(s, c, req, done) -> s.hasUserPermissions(c, req, done),
resp -> resp.getHasUserPermissionList()))
.call();
}
}

View File

@ -25,6 +25,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Get
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceRequest;
@ -696,4 +698,10 @@ public class ShortCircuitMasterConnection implements MasterKeepAliveConnection {
GetUserPermissionsRequest request) throws ServiceException {
return stub.getUserPermissions(controller, request);
}
@Override
public HasUserPermissionsResponse hasUserPermissions(RpcController controller,
HasUserPermissionsRequest request) throws ServiceException {
return stub.hasUserPermissions(controller, request);
}
}

View File

@ -392,19 +392,9 @@ public class AccessControlClient {
if (StringUtils.isEmpty(tableName) || StringUtils.isEmpty(userName)) {
throw new IllegalArgumentException("Table and user name can't be null or empty.");
}
boolean hasPermission = false;
/**
* todo: pass an rpccontroller hbaserpccontroller controller = ((clusterconnection)
* connection).getrpccontrollerfactory().newcontroller();
*/
try (Table table = connection.getTable(ACL_TABLE_NAME)) {
CoprocessorRpcChannel service = table.coprocessorService(HConstants.EMPTY_START_ROW);
BlockingInterface protocol =
AccessControlProtos.AccessControlService.newBlockingStub(service);
// Check whether user has permission
hasPermission = AccessControlUtil.hasPermission(null, protocol, TableName.valueOf(tableName),
columnFamily, columnQualifier, userName, actions);
}
return hasPermission;
List<Permission> permissions = new ArrayList<>(1);
permissions.add(Permission.newBuilder(TableName.valueOf(tableName)).withFamily(columnFamily)
.withQualifier(columnQualifier).withActions(actions).build());
return connection.getAdmin().hasUserPermissions(userName, permissions).get(0);
}
}

View File

@ -815,7 +815,9 @@ public class AccessControlUtil {
* @param actions Actions
* @return true if access allowed, otherwise false
* @throws ServiceException
* @deprecated Use {@link Admin#hasUserPermissions(String, List)} instead.
*/
@Deprecated
public static boolean hasPermission(RpcController controller,
AccessControlService.BlockingInterface protocol, TableName tableName, byte[] columnFamily,
byte[] columnQualifier, String userName, Permission.Action[] actions)

View File

@ -31,6 +31,7 @@ import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
@ -318,4 +319,16 @@ public class ShadedAccessControlUtil {
}
return builder.build();
}
public static HasUserPermissionsRequest buildHasUserPermissionsRequest(String userName,
List<Permission> permissions) {
HasUserPermissionsRequest.Builder builder = HasUserPermissionsRequest.newBuilder();
if (userName != null && !userName.isEmpty()) {
builder.setUserName(ByteString.copyFromUtf8(userName));
}
for (Permission permission : permissions) {
builder.addPermission(toPermission(permission));
}
return builder.build();
}
}

View File

@ -119,6 +119,15 @@ message CheckPermissionsRequest {
message CheckPermissionsResponse {
}
message HasUserPermissionsRequest {
optional bytes user_name = 1;
repeated Permission permission = 2;
}
message HasUserPermissionsResponse {
repeated bool has_user_permission = 1;
}
service AccessControlService {
rpc Grant(GrantRequest)
returns (GrantResponse);

View File

@ -1033,6 +1033,8 @@ service MasterService {
rpc Revoke(RevokeRequest) returns (RevokeResponse);
rpc GetUserPermissions (GetUserPermissionsRequest) returns (GetUserPermissionsResponse);
rpc HasUserPermissions (HasUserPermissionsRequest) returns (HasUserPermissionsResponse);
}
// HBCK Service definitions.

View File

@ -37,6 +37,7 @@ import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.GlobalQuotaSettings;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
@ -1662,4 +1663,24 @@ public interface MasterObserver {
String userName, String namespace, TableName tableName, byte[] family, byte[] qualifier)
throws IOException {
}
/*
* Called before checking if user has permissions.
* @param ctx the coprocessor instance's environment
* @param userName the user name
* @param permissions the permission list
*/
default void preHasUserPermissions(ObserverContext<MasterCoprocessorEnvironment> ctx,
String userName, List<Permission> permissions) throws IOException {
}
/**
* Called after checking if user has permissions.
* @param ctx the coprocessor instance's environment
* @param userName the user name
* @param permissions the permission list
*/
default void postHasUserPermissions(ObserverContext<MasterCoprocessorEnvironment> ctx,
String userName, List<Permission> permissions) throws IOException {
}
}

View File

@ -58,6 +58,7 @@ import org.apache.hadoop.hbase.quotas.GlobalQuotaSettings;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
@ -1912,4 +1913,24 @@ public class MasterCoprocessorHost
}
});
}
public void preHasUserPermissions(String userName, List<Permission> permissions)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
observer.preHasUserPermissions(this, userName, permissions);
}
});
}
public void postHasUserPermissions(String userName, List<Permission> permissions)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
observer.postHasUserPermissions(this, userName, permissions);
}
});
}
}

View File

@ -94,6 +94,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.security.Superusers;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.security.access.AccessChecker.InputUser;
import org.apache.hadoop.hbase.security.access.AccessControlLists;
import org.apache.hadoop.hbase.security.access.AccessController;
import org.apache.hadoop.hbase.security.access.Permission;
@ -125,6 +126,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Get
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeResponse;
@ -2628,6 +2631,47 @@ public class MasterRpcServices extends RSRpcServices
}
}
@Override
public HasUserPermissionsResponse hasUserPermissions(RpcController controller,
HasUserPermissionsRequest request) throws ServiceException {
try {
User caller = RpcServer.getRequestUser().orElse(null);
String userName =
request.hasUserName() ? request.getUserName().toStringUtf8() : caller.getShortName();
List<Permission> permissions = new ArrayList<>();
for (int i = 0; i < request.getPermissionCount(); i++) {
permissions.add(ShadedAccessControlUtil.toPermission(request.getPermission(i)));
}
if (master.cpHost != null) {
master.getMasterCoprocessorHost().preHasUserPermissions(userName, permissions);
}
if (!caller.getShortName().equals(userName)) {
List<String> groups = AccessChecker.getUserGroups(userName);
caller = new InputUser(userName, groups.toArray(new String[groups.size()]));
}
List<Boolean> hasUserPermissions = new ArrayList<>();
if (accessChecker != null) {
for (Permission permission : permissions) {
boolean hasUserPermission =
accessChecker.hasUserPermission(caller, "hasUserPermissions", permission);
hasUserPermissions.add(hasUserPermission);
}
} else {
for (int i = 0; i < permissions.size(); i++) {
hasUserPermissions.add(true);
}
}
if (master.cpHost != null) {
master.getMasterCoprocessorHost().postHasUserPermissions(userName, permissions);
}
HasUserPermissionsResponse.Builder builder =
HasUserPermissionsResponse.newBuilder().addAllHasUserPermission(hasUserPermissions);
return builder.build();
} catch (IOException ioe) {
throw new ServiceException(ioe);
}
}
private boolean containMetaWals(ServerName serverName) throws IOException {
Path logDir = new Path(master.getWALRootDir(),
AbstractFSWALProvider.getWALDirectoryName(serverName.toString()));

View File

@ -26,9 +26,13 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.AuthUtil;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
@ -39,12 +43,14 @@ import org.apache.hadoop.hbase.security.Superusers;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider;
import org.apache.hadoop.hbase.security.access.Permission.Action;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
import org.apache.hadoop.security.Groups;
import org.apache.hadoop.security.HadoopKerberosName;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet;
@InterfaceAudience.Private
public final class AccessChecker {
@ -526,4 +532,162 @@ public final class AccessChecker {
return new ArrayList<>();
}
}
/**
* Authorizes that if the current user has the given permissions.
* @param user Active user to which authorization checks should be applied
* @param request Request type
* @param permission Actions being requested
* @return True if the user has the specific permission
*/
public boolean hasUserPermission(User user, String request, Permission permission) {
if (!authorizationEnabled) {
return true;
}
if (permission instanceof TablePermission) {
TablePermission tPerm = (TablePermission) permission;
for (Permission.Action action : permission.getActions()) {
AuthResult authResult = permissionGranted(request, user, action, tPerm.getTableName(),
tPerm.getFamily(), tPerm.getQualifier());
AccessChecker.logResult(authResult);
if (!authResult.isAllowed()) {
return false;
}
}
} else if (permission instanceof NamespacePermission) {
NamespacePermission nsPerm = (NamespacePermission) permission;
AuthResult authResult;
for (Action action : nsPerm.getActions()) {
if (getAuthManager().authorizeUserNamespace(user, nsPerm.getNamespace(), action)) {
authResult =
AuthResult.allow(request, "Namespace action allowed", user, action, null, null);
} else {
authResult =
AuthResult.deny(request, "Namespace action denied", user, action, null, null);
}
AccessChecker.logResult(authResult);
if (!authResult.isAllowed()) {
return false;
}
}
} else {
AuthResult authResult;
for (Permission.Action action : permission.getActions()) {
if (getAuthManager().authorizeUserGlobal(user, action)) {
authResult = AuthResult.allow(request, "Global action allowed", user, action, null, null);
} else {
authResult = AuthResult.deny(request, "Global action denied", user, action, null, null);
}
AccessChecker.logResult(authResult);
if (!authResult.isAllowed()) {
return false;
}
}
}
return true;
}
private AuthResult permissionGranted(String request, User user, Action permRequest,
TableName tableName, byte[] family, byte[] qualifier) {
Map<byte[], ? extends Collection<byte[]>> map = makeFamilyMap(family, qualifier);
return permissionGranted(request, user, permRequest, tableName, map);
}
/**
* Check the current user for authorization to perform a specific action against the given set of
* row data.
* <p>
* Note: Ordering of the authorization checks has been carefully optimized to short-circuit the
* most common requests and minimize the amount of processing required.
* </p>
* @param request User request
* @param user User name
* @param permRequest the action being requested
* @param tableName Table name
* @param families the map of column families to qualifiers present in the request
* @return an authorization result
*/
public AuthResult permissionGranted(String request, User user, Action permRequest,
TableName tableName, Map<byte[], ? extends Collection<?>> families) {
if (!authorizationEnabled) {
return AuthResult.allow(request, "All users allowed because authorization is disabled", user,
permRequest, tableName, families);
}
// 1. All users need read access to hbase:meta table.
// this is a very common operation, so deal with it quickly.
if (TableName.META_TABLE_NAME.equals(tableName)) {
if (permRequest == Action.READ) {
return AuthResult.allow(request, "All users allowed", user, permRequest, tableName,
families);
}
}
if (user == null) {
return AuthResult.deny(request, "No user associated with request!", null, permRequest,
tableName, families);
}
// 2. check for the table-level, if successful we can short-circuit
if (getAuthManager().authorizeUserTable(user, tableName, permRequest)) {
return AuthResult.allow(request, "Table permission granted", user, permRequest, tableName,
families);
}
// 3. check permissions against the requested families
if (families != null && families.size() > 0) {
// all families must pass
for (Map.Entry<byte[], ? extends Collection<?>> family : families.entrySet()) {
// a) check for family level access
if (getAuthManager().authorizeUserTable(user, tableName, family.getKey(), permRequest)) {
continue; // family-level permission overrides per-qualifier
}
// b) qualifier level access can still succeed
if ((family.getValue() != null) && (family.getValue().size() > 0)) {
if (family.getValue() instanceof Set) {
// for each qualifier of the family
Set<byte[]> familySet = (Set<byte[]>) family.getValue();
for (byte[] qualifier : familySet) {
if (!getAuthManager().authorizeUserTable(user, tableName, family.getKey(), qualifier,
permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user, permRequest,
tableName, makeFamilyMap(family.getKey(), qualifier));
}
}
} else if (family.getValue() instanceof List) { // List<Cell>
List<Cell> cellList = (List<Cell>) family.getValue();
for (Cell cell : cellList) {
if (!getAuthManager().authorizeUserTable(user, tableName, family.getKey(),
CellUtil.cloneQualifier(cell), permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user, permRequest,
tableName, makeFamilyMap(family.getKey(), CellUtil.cloneQualifier(cell)));
}
}
}
} else {
// no qualifiers and family-level check already failed
return AuthResult.deny(request, "Failed family check", user, permRequest, tableName,
makeFamilyMap(family.getKey(), null));
}
}
// all family checks passed
return AuthResult.allow(request, "All family checks passed", user, permRequest, tableName,
families);
}
// 4. no families to check and table level access failed
return AuthResult.deny(request, "No families to check and table permission failed", user,
permRequest, tableName, families);
}
private Map<byte[], ? extends Collection<byte[]>> makeFamilyMap(byte[] family, byte[] qualifier) {
if (family == null) {
return null;
}
Map<byte[], Collection<byte[]>> familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
familyMap.put(family, qualifier != null ? ImmutableSet.of(qualifier) : null);
return familyMap;
}
}

View File

@ -141,7 +141,6 @@ import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
import org.apache.hbase.thirdparty.com.google.common.collect.MapMaker;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
/**
* Provides basic authorization checks for data access and administrative
@ -298,93 +297,6 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
}
}
/**
* Check the current user for authorization to perform a specific action against the given set of
* row data.
* <p>
* Note: Ordering of the authorization checks has been carefully optimized to short-circuit the
* most common requests and minimize the amount of processing required.
* </p>
* @param request User request
* @param user User name
* @param permRequest the action being requested
* @param e the coprocessor environment
* @param tableName Table name
* @param families the map of column families to qualifiers present in the request
* @return an authorization result
*/
private AuthResult permissionGranted(String request, User user, Action permRequest,
RegionCoprocessorEnvironment e, TableName tableName,
Map<byte[], ? extends Collection<?>> families) {
// 1. All users need read access to hbase:meta table.
// this is a very common operation, so deal with it quickly.
if (TableName.META_TABLE_NAME.equals(tableName)) {
if (permRequest == Action.READ) {
return AuthResult.allow(request, "All users allowed", user, permRequest, tableName,
families);
}
}
if (user == null) {
return AuthResult.deny(request, "No user associated with request!", null,
permRequest, tableName, families);
}
// 2. check for the table-level, if successful we can short-circuit
if (getAuthManager().authorizeUserTable(user, tableName, permRequest)) {
return AuthResult.allow(request, "Table permission granted", user,
permRequest, tableName, families);
}
// 3. check permissions against the requested families
if (families != null && families.size() > 0) {
// all families must pass
for (Map.Entry<byte [], ? extends Collection<?>> family : families.entrySet()) {
// a) check for family level access
if (getAuthManager().authorizeUserTable(user, tableName, family.getKey(),
permRequest)) {
continue; // family-level permission overrides per-qualifier
}
// b) qualifier level access can still succeed
if ((family.getValue() != null) && (family.getValue().size() > 0)) {
if (family.getValue() instanceof Set) {
// for each qualifier of the family
Set<byte[]> familySet = (Set<byte[]>)family.getValue();
for (byte[] qualifier : familySet) {
if (!getAuthManager().authorizeUserTable(user, tableName,
family.getKey(), qualifier, permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user,
permRequest, tableName, makeFamilyMap(family.getKey(), qualifier));
}
}
} else if (family.getValue() instanceof List) { // List<Cell>
List<Cell> cellList = (List<Cell>)family.getValue();
for (Cell cell : cellList) {
if (!getAuthManager().authorizeUserTable(user, tableName, family.getKey(),
CellUtil.cloneQualifier(cell), permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user, permRequest,
tableName, makeFamilyMap(family.getKey(), CellUtil.cloneQualifier(cell)));
}
}
}
} else {
// no qualifiers and family-level check already failed
return AuthResult.deny(request, "Failed family check", user, permRequest,
tableName, makeFamilyMap(family.getKey(), null));
}
}
// all family checks passed
return AuthResult.allow(request, "All family checks passed", user, permRequest,
tableName, families);
}
// 4. no families to check and table level access failed
return AuthResult.deny(request, "No families to check and table permission failed",
user, permRequest, tableName, families);
}
/**
* Check the current user for authorization to perform a specific action
* against the given set of row data.
@ -400,7 +312,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
Map<byte [], ? extends Collection<?>> families, Action... actions) {
AuthResult result = null;
for (Action action: actions) {
result = permissionGranted(opType.toString(), user, action, e,
result = accessChecker.permissionGranted(opType.toString(), user, action,
e.getRegion().getRegionInfo().getTable(), families);
if (!result.isAllowed()) {
return result;
@ -2186,76 +2098,40 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
done.run(response);
}
/**
* @deprecated Use {@link Admin#hasUserPermissions(List)} instead.
*/
@Deprecated
@Override
public void checkPermissions(RpcController controller,
AccessControlProtos.CheckPermissionsRequest request,
RpcCallback<AccessControlProtos.CheckPermissionsResponse> done) {
Permission[] permissions = new Permission[request.getPermissionCount()];
for (int i=0; i < request.getPermissionCount(); i++) {
permissions[i] = AccessControlUtil.toPermission(request.getPermission(i));
}
AccessControlProtos.CheckPermissionsRequest request,
RpcCallback<AccessControlProtos.CheckPermissionsResponse> done) {
AccessControlProtos.CheckPermissionsResponse response = null;
try {
User user = RpcServer.getRequestUser().orElse(null);
TableName tableName = regionEnv.getRegion().getTableDescriptor().getTableName();
for (Permission permission : permissions) {
List<Permission> permissions = new ArrayList<>();
for (int i = 0; i < request.getPermissionCount(); i++) {
Permission permission = AccessControlUtil.toPermission(request.getPermission(i));
permissions.add(permission);
if (permission instanceof TablePermission) {
// Check table permissions
TablePermission tperm = (TablePermission) permission;
for (Action action : permission.getActions()) {
if (!tperm.getTableName().equals(tableName)) {
throw new CoprocessorException(AccessController.class, String.format("This method "
+ "can only execute at the table specified in TablePermission. " +
"Table of the region:%s , requested table:%s", tableName,
tperm.getTableName()));
}
Map<byte[], Set<byte[]>> familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
if (tperm.getFamily() != null) {
if (tperm.getQualifier() != null) {
Set<byte[]> qualifiers = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
qualifiers.add(tperm.getQualifier());
familyMap.put(tperm.getFamily(), qualifiers);
} else {
familyMap.put(tperm.getFamily(), null);
}
}
AuthResult result = permissionGranted("checkPermissions", user, action, regionEnv,
regionEnv.getRegion().getRegionInfo().getTable(), familyMap);
AccessChecker.logResult(result);
if (!result.isAllowed()) {
// Even if passive we need to throw an exception here, we support checking
// effective permissions, so throw unconditionally
throw new AccessDeniedException("Insufficient permissions (table=" + tableName +
(familyMap.size() > 0 ? ", family: " + result.toFamilyString() : "") +
", action=" + action.toString() + ")");
}
}
} else {
// Check global permissions
for (Action action : permission.getActions()) {
AuthResult result;
if (getAuthManager().authorizeUserGlobal(user, action)) {
result = AuthResult.allow("checkPermissions", "Global action allowed", user,
action, null, null);
} else {
result = AuthResult.deny("checkPermissions", "Global action denied", user, action,
null, null);
}
AccessChecker.logResult(result);
if (!result.isAllowed()) {
// Even if passive we need to throw an exception here, we support checking
// effective permissions, so throw unconditionally
throw new AccessDeniedException("Insufficient permissions (action=" +
action.toString() + ")");
}
if (!tperm.getTableName().equals(tableName)) {
throw new CoprocessorException(AccessController.class,
String.format(
"This method can only execute at the table specified in "
+ "TablePermission. Table of the region:%s , requested table:%s",
tableName, tperm.getTableName()));
}
}
}
for (Permission permission : permissions) {
boolean hasPermission =
accessChecker.hasUserPermission(user, "checkPermissions", permission);
if (!hasPermission) {
throw new AccessDeniedException("Insufficient permissions " + permission.toString());
}
}
response = AccessControlProtos.CheckPermissionsResponse.getDefaultInstance();
} catch (IOException ioe) {
CoprocessorRpcUtils.setControllerException(controller, ioe);
@ -2555,6 +2431,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
return userProvider.getCurrent();
}
/**
* @deprecated Use {@link Admin#hasUserPermissions(String, List)} instead.
*/
@Deprecated
@Override
public void hasPermission(RpcController controller, HasPermissionRequest request,
RpcCallback<HasPermissionResponse> done) {
@ -2568,33 +2448,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
AccessControlProtos.HasPermissionResponse response = null;
try {
User caller = RpcServer.getRequestUser().orElse(null);
// User instance for the input user name
User filterUser = accessChecker.validateCallerWithFilterUser(caller, tPerm, inputUserName);
// Initialize family and qualifier map
Map<byte[], Set<byte[]>> familyMap = new TreeMap<byte[], Set<byte[]>>(Bytes.BYTES_COMPARATOR);
if (tPerm.getFamily() != null) {
if (tPerm.getQualifier() != null) {
Set<byte[]> qualifiers = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
qualifiers.add(tPerm.getQualifier());
familyMap.put(tPerm.getFamily(), qualifiers);
} else {
familyMap.put(tPerm.getFamily(), null);
}
}
// Iterate each action and check whether permission granted
boolean hasPermission = false;
for (Action action : tPerm.getActions()) {
AuthResult result = permissionGranted("hasPermission", filterUser, action, regionEnv,
tPerm.getTableName(), familyMap);
if (!result.isAllowed()) {
hasPermission = false;
// Break the loop is any action is not allowed
break;
}
hasPermission = true;
}
List<Permission> permissions = Lists.newArrayList(tPerm);
preHasUserPermissions(caller, inputUserName, permissions);
boolean hasPermission = regionEnv.getConnection().getAdmin()
.hasUserPermissions(inputUserName, permissions).get(0);
response = ResponseConverter.buildHasPermissionResponse(hasPermission);
} catch (IOException ioe) {
ResponseConverter.setControllerException(controller, ioe);
@ -2656,4 +2513,48 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
accessChecker.requirePermission(caller, "getUserPermissions", userName, Action.ADMIN);
}
}
@Override
public void preHasUserPermissions(ObserverContext<MasterCoprocessorEnvironment> ctx,
String userName, List<Permission> permissions) throws IOException {
preHasUserPermissions(getActiveUser(ctx), userName, permissions);
}
private void preHasUserPermissions(User caller, String userName, List<Permission> permissions)
throws IOException {
String request = "hasUserPermissions";
for (Permission permission : permissions) {
if (!caller.getShortName().equals(userName)) {
// User should have admin privilege if checking permission for other users
if (permission instanceof TablePermission) {
TablePermission tPerm = (TablePermission) permission;
accessChecker.requirePermission(caller, request, tPerm.getTableName(), tPerm.getFamily(),
tPerm.getQualifier(), userName, Action.ADMIN);
} else if (permission instanceof NamespacePermission) {
NamespacePermission nsPerm = (NamespacePermission) permission;
accessChecker.requireNamespacePermission(caller, request, nsPerm.getNamespace(), userName,
Action.ADMIN);
} else {
accessChecker.requirePermission(caller, request, userName, Action.ADMIN);
}
} else {
// User don't need ADMIN privilege for self check.
// Setting action as null in AuthResult to display empty action in audit log
AuthResult result;
if (permission instanceof TablePermission) {
TablePermission tPerm = (TablePermission) permission;
result = AuthResult.allow(request, "Self user validation allowed", caller, null,
tPerm.getTableName(), tPerm.getFamily(), tPerm.getQualifier());
} else if (permission instanceof NamespacePermission) {
NamespacePermission nsPerm = (NamespacePermission) permission;
result = AuthResult.allow(request, "Self user validation allowed", caller, null,
nsPerm.getNamespace());
} else {
result = AuthResult.allow(request, "Self user validation allowed", caller, null, null,
null, null);
}
accessChecker.logResult(result);
}
}
}
}

View File

@ -12,14 +12,19 @@
package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessControlLists;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.SecureTestUtil;
import org.apache.hadoop.hbase.security.access.SecureTestUtil.AccessTestAction;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
@ -29,6 +34,7 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
@RunWith(Parameterized.class)
@Category({ ClientTests.class, SmallTests.class })
@ -47,12 +53,16 @@ public class TestAsyncAccessControlAdminApi extends TestAsyncAdminBase {
}
@Test
public void testGrant() throws Exception {
public void test() throws Exception {
TableName tableName = TableName.valueOf("test-table");
String user = "test-user";
UserPermission userPermission = new UserPermission(user,
Permission.newBuilder(tableName).withActions(Permission.Action.READ).build());
// grant user table permission
String userName1 = "user1";
String userName2 = "user2";
User user2 = User.createUserForTesting(TEST_UTIL.getConfiguration(), userName2, new String[0]);
Permission permission =
Permission.newBuilder(tableName).withActions(Permission.Action.READ).build();
UserPermission userPermission = new UserPermission(userName1, permission);
// grant user1 table permission
admin.grant(userPermission, false).get();
// get table permissions
@ -61,14 +71,57 @@ public class TestAsyncAccessControlAdminApi extends TestAsyncAdminBase {
assertEquals(1, userPermissions.size());
assertEquals(userPermission, userPermissions.get(0));
// get user table permissions
userPermissions = admin.getUserPermissions(
GetUserPermissionsRequest.newBuilder(tableName).withUserName(user).build()).get();
// get table permissions
userPermissions =
admin
.getUserPermissions(
GetUserPermissionsRequest.newBuilder(tableName).withUserName(userName1).build())
.get();
assertEquals(1, userPermissions.size());
assertEquals(userPermission, userPermissions.get(0));
userPermissions = admin.getUserPermissions(
GetUserPermissionsRequest.newBuilder(tableName).withUserName("u").build()).get();
userPermissions =
admin
.getUserPermissions(
GetUserPermissionsRequest.newBuilder(tableName).withUserName(userName2).build())
.get();
assertEquals(0, userPermissions.size());
// has user permission
List<Permission> permissions = Lists.newArrayList(permission);
boolean hasPermission =
admin.hasUserPermissions(userName1, permissions).get().get(0).booleanValue();
assertTrue(hasPermission);
hasPermission = admin.hasUserPermissions(userName2, permissions).get().get(0).booleanValue();
assertFalse(hasPermission);
AccessTestAction hasPermissionAction = new AccessTestAction() {
@Override
public Object run() throws Exception {
try (AsyncConnection conn =
ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get()) {
return conn.getAdmin().hasUserPermissions(userName1, permissions).get().get(0);
}
}
};
try {
user2.runAs(hasPermissionAction);
fail("Should not come here");
} catch (Exception e) {
LOG.error("Call has permission error", e);
}
// check permission
admin.hasUserPermissions(permissions);
AccessTestAction checkPermissionsAction = new AccessTestAction() {
@Override
public Object run() throws Exception {
try (AsyncConnection conn =
ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get()) {
return conn.getAdmin().hasUserPermissions(permissions).get().get(0);
}
}
};
assertFalse((Boolean) user2.runAs(checkPermissionsAction));
}
}

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.security.access;
import com.google.protobuf.ServiceException;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.PrivilegedActionException;
@ -28,9 +29,6 @@ import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import com.google.protobuf.BlockingRpcChannel;
import com.google.protobuf.ServiceException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.HBaseTestingUtility;
@ -54,14 +52,9 @@ import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.MasterObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.security.AccessDeniedException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.Permission.Action;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
@ -140,36 +133,6 @@ public class SecureTestUtil {
}
}
public static void checkTablePerms(Configuration conf, TableName table, byte[] family, byte[] column,
Permission.Action... actions) throws IOException {
Permission[] perms = new Permission[actions.length];
for (int i = 0; i < actions.length; i++) {
perms[i] = Permission.newBuilder(table).withFamily(family).withQualifier(column)
.withActions(actions[i]).build();
}
checkTablePerms(conf, table, perms);
}
public static void checkTablePerms(Configuration conf, TableName table, Permission... perms)
throws IOException {
CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
for (Permission p : perms) {
request.addPermission(AccessControlUtil.toPermission(p));
}
try (Connection connection = ConnectionFactory.createConnection(conf)) {
try (Table acl = connection.getTable(table)) {
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
try {
protocol.checkPermissions(null, request.build());
} catch (ServiceException se) {
ProtobufUtil.toIOException(se);
}
}
}
}
/**
* An AccessTestAction performs an action that will be examined to confirm
* the results conform to expected access rights.
@ -854,25 +817,7 @@ public class SecureTestUtil {
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(AccessControlUtil.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);
}
}
checkPermissions(testUtil.getConfiguration(), perms);
}
public static void checkTablePerms(HBaseTestingUtility testUtil, TableName table, byte[] family,
@ -882,26 +827,23 @@ public class SecureTestUtil {
perms[i] = Permission.newBuilder(table).withFamily(family).withQualifier(column)
.withActions(actions[i]).build();
}
checkTablePerms(testUtil, table, perms);
checkTablePerms(testUtil, perms);
}
public static void checkTablePerms(HBaseTestingUtility testUtil, TableName table,
Permission... perms) throws IOException {
CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
for (Permission p : perms) {
request.addPermission(AccessControlUtil.toPermission(p));
}
public static void checkTablePerms(HBaseTestingUtility testUtil, Permission... perms)
throws IOException {
checkPermissions(testUtil.getConfiguration(), perms);
}
try(Connection conn = ConnectionFactory.createConnection(testUtil.getConfiguration());
Table acl = conn.getTable(table)) {
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
try {
protocol.checkPermissions(null, request.build());
} catch (ServiceException se) {
ProtobufUtil.toIOException(se);
private static void checkPermissions(Configuration conf, Permission... perms) throws IOException {
try (Connection conn = ConnectionFactory.createConnection(conf)) {
List<Boolean> hasUserPermissions =
conn.getAdmin().hasUserPermissions(Lists.newArrayList(perms));
for (int i = 0; i < hasUserPermissions.size(); i++) {
if (!hasUserPermissions.get(i).booleanValue()) {
throw new AccessDeniedException("Insufficient permissions " + perms[i]);
}
}
}
}
}

View File

@ -1844,7 +1844,7 @@ public class TestAccessController extends SecureTestUtil {
AccessTestAction multiQualifierRead = new AccessTestAction() {
@Override
public Void run() throws Exception {
checkTablePerms(TEST_UTIL, TEST_TABLE,
checkTablePerms(TEST_UTIL,
new Permission[] {
Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_Q1)
.withActions(Permission.Action.READ).build(),
@ -1857,8 +1857,7 @@ public class TestAccessController extends SecureTestUtil {
AccessTestAction globalAndTableRead = new AccessTestAction() {
@Override
public Void run() throws Exception {
checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] {
new Permission(Permission.Action.READ),
checkTablePerms(TEST_UTIL, new Permission[] { new Permission(Permission.Action.READ),
Permission.newBuilder(TEST_TABLE).withActions(Permission.Action.READ).build() });
return null;
}
@ -1867,7 +1866,7 @@ public class TestAccessController extends SecureTestUtil {
AccessTestAction noCheck = new AccessTestAction() {
@Override
public Void run() throws Exception {
checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[0]);
checkTablePerms(TEST_UTIL, new Permission[0]);
return null;
}
};
@ -3333,7 +3332,7 @@ public class TestAccessController extends SecureTestUtil {
TEST_FAMILY, TEST_QUALIFIER, Permission.Action.READ, Permission.Action.WRITE);
// Verify action privilege
AccessTestAction hasPermissionAction = new AccessTestAction() {
AccessTestAction hasPermissionActionCP = new AccessTestAction() {
@Override
public Object run() throws Exception {
try (Connection conn = ConnectionFactory.createConnection(conf);
@ -3348,6 +3347,21 @@ public class TestAccessController extends SecureTestUtil {
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);

View File

@ -250,9 +250,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkGlobalAdmin, SUPERUSER, USER_ADMIN);
verifyDenied(checkGlobalAdmin, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL,
USER_NONE);
verifyAllowed(checkGlobalAdmin, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkGlobalRead = new AccessTestAction() {
@Override
@ -262,9 +261,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkGlobalRead, SUPERUSER, USER_ADMIN);
verifyDenied(checkGlobalRead, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL,
USER_NONE);
verifyAllowed(checkGlobalRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
USER_QUAL, USER_NONE);
AccessTestAction checkGlobalReadWrite = new AccessTestAction() {
@Override
@ -274,9 +272,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkGlobalReadWrite, SUPERUSER, USER_ADMIN);
verifyDenied(checkGlobalReadWrite, USER_OWNER, USER_CREATE, USER_RW, USER_RO, USER_QUAL,
USER_NONE);
verifyAllowed(checkGlobalReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkTableAdmin = new AccessTestAction() {
@Override
@ -287,8 +284,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkTableAdmin, SUPERUSER, USER_ADMIN, USER_OWNER);
verifyDenied(checkTableAdmin, USER_CREATE, USER_RW, USER_RO, USER_QUAL, USER_NONE);
verifyAllowed(checkTableAdmin, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
USER_QUAL, USER_NONE);
AccessTestAction checkTableCreate = new AccessTestAction() {
@Override
@ -299,8 +296,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkTableCreate, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
verifyDenied(checkTableCreate, USER_RW, USER_RO, USER_QUAL, USER_NONE);
verifyAllowed(checkTableCreate, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkTableRead = new AccessTestAction() {
@Override
@ -311,8 +308,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkTableRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
verifyDenied(checkTableRead, USER_RW, USER_RO, USER_QUAL, USER_NONE);
verifyAllowed(checkTableRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
USER_QUAL, USER_NONE);
AccessTestAction checkTableReadWrite = new AccessTestAction() {
@Override
@ -323,8 +320,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkTableReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
verifyDenied(checkTableReadWrite, USER_RW, USER_RO, USER_QUAL, USER_NONE);
verifyAllowed(checkTableReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkColumnRead = new AccessTestAction() {
@Override
@ -335,9 +332,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkColumnRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO);
verifyDenied(checkColumnRead, USER_QUAL, USER_NONE);
verifyAllowed(checkColumnRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO,
USER_QUAL, USER_NONE);
AccessTestAction checkColumnReadWrite = new AccessTestAction() {
@Override
@ -348,9 +344,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkColumnReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
USER_RW);
verifyDenied(checkColumnReadWrite, USER_RO, USER_QUAL, USER_NONE);
verifyAllowed(checkColumnReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkQualifierRead = new AccessTestAction() {
@Override
@ -362,8 +357,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
};
verifyAllowed(checkQualifierRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL);
verifyDenied(checkQualifierRead, USER_NONE);
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkQualifierReadWrite = new AccessTestAction() {
@Override
@ -374,14 +368,13 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkQualifierReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
USER_RW, USER_QUAL);
verifyDenied(checkQualifierReadWrite, USER_RO, USER_NONE);
verifyAllowed(checkQualifierReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_QUAL, USER_RO, USER_NONE);
AccessTestAction checkMultiQualifierRead = new AccessTestAction() {
@Override
public Void run() throws Exception {
checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(),
checkTablePerms(TEST_UTIL,
new Permission[] {
Permission.newBuilder(TEST_TABLE.getTableName()).withFamily(TEST_FAMILY)
.withQualifier(TEST_Q1).withActions(Action.READ).build(),
@ -391,14 +384,13 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyAllowed(checkMultiQualifierRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
USER_RW, USER_RO);
verifyDenied(checkMultiQualifierRead, USER_QUAL, USER_NONE);
verifyAllowed(checkMultiQualifierRead, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW,
USER_RO, USER_QUAL, USER_NONE);
AccessTestAction checkMultiQualifierReadWrite = new AccessTestAction() {
@Override
public Void run() throws Exception {
checkTablePerms(TEST_UTIL, TEST_TABLE.getTableName(),
checkTablePerms(TEST_UTIL,
new Permission[] {
Permission.newBuilder(TEST_TABLE.getTableName()).withFamily(TEST_FAMILY)
.withQualifier(TEST_Q1)
@ -411,8 +403,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
};
verifyAllowed(checkMultiQualifierReadWrite, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE,
USER_RW);
verifyDenied(checkMultiQualifierReadWrite, USER_RO, USER_QUAL, USER_NONE);
USER_RW, USER_RO, USER_QUAL, USER_NONE);
}
/** Test grants and revocations with authorization disabled */
@ -424,7 +415,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
User tblUser = User.createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser",
new String[0]);
// If we check now, the test user won't have permissions
// If we check now, the test user have permissions because authorization is disabled
AccessTestAction checkTableRead = new AccessTestAction() {
@Override
@ -435,7 +426,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
}
};
verifyDenied(tblUser, checkTableRead);
verifyAllowed(tblUser, checkTableRead);
// An actual read won't be denied
@ -469,7 +460,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
// Now the permission check will indicate revocation but the actual op will still succeed
verifyDenied(tblUser, checkTableRead);
verifyAllowed(tblUser, checkTableRead);
verifyAllowed(tblUser, tableRead);
}

View File

@ -57,6 +57,7 @@ import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
import org.apache.hadoop.hbase.thrift2.ThriftUtilities;
@ -1121,6 +1122,11 @@ public class ThriftAdmin implements Admin {
throw new NotImplementedException("getUserPermissions not supported in ThriftAdmin");
}
@Override
public List<Boolean> hasUserPermissions(String userName, List<Permission> permissions) {
throw new NotImplementedException("hasUserPermissions not supported in ThriftAdmin");
}
@Override
public Future<Void> splitRegionAsync(byte[] regionName) throws IOException {
return splitRegionAsync(regionName, null);