From 20cd40d412915ee3cdbc58bd8e548fe775f7f27f Mon Sep 17 00:00:00 2001 From: Guangxu Cheng Date: Tue, 19 Dec 2017 14:45:02 +0800 Subject: [PATCH] HBASE-19483 Add proper privilege check for rsgroup commands --- .../hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java | 103 ++- .../hadoop/hbase/rsgroup/RSGroupAdminServer.java | 39 +- .../hadoop/hbase/coprocessor/MasterObserver.java | 71 +++ .../hadoop/hbase/master/MasterCoprocessorHost.java | 89 +++ .../hadoop/hbase/master/MasterRpcServices.java | 3 +- .../hbase/security/access/AccessChecker.java | 410 ++++++++++++ .../hbase/security/access/AccessController.java | 689 +++++++-------------- .../asciidoc/_chapters/appendix_acl_matrix.adoc | 11 + 8 files changed, 935 insertions(+), 480 deletions(-) create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessChecker.java diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java index e332f5ccb0..a9a1f54239 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java @@ -75,7 +75,11 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGro import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse; +import org.apache.hadoop.hbase.security.access.AccessChecker; +import org.apache.hadoop.hbase.security.access.AccessController; +import org.apache.hadoop.hbase.security.access.Permission.Action; import org.apache.hadoop.hbase.shaded.com.google.common.collect.Sets; +import org.apache.hadoop.hbase.zookeeper.ZKWatcher; import org.apache.yetus.audience.InterfaceAudience; // TODO: Encapsulate MasterObserver functions into separate subclass. @@ -90,12 +94,15 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver { private RSGroupInfoManager groupInfoManager; private RSGroupAdminServer groupAdminServer; private final RSGroupAdminService groupAdminService = new RSGroupAdminServiceImpl(); + private boolean aclEnabled; + private AccessChecker accessChecker; @Override public void start(CoprocessorEnvironment env) throws IOException { if (!(env instanceof HasMasterServices)) { throw new IOException("Does not implement HMasterServices"); } + master = ((HasMasterServices)env).getMasterServices(); groupInfoManager = RSGroupInfoManagerImpl.getInstance(master); groupAdminServer = new RSGroupAdminServer(master, groupInfoManager); @@ -104,6 +111,13 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver { if (!RSGroupableBalancer.class.isAssignableFrom(clazz)) { throw new IOException("Configured balancer does not support RegionServer groups."); } + aclEnabled = master.getMasterCoprocessorHost().findCoprocessor(AccessController.class) != null; + if (aclEnabled) { + ZKWatcher zk = ((HasMasterServices)env).getMasterServices().getZooKeeper(); + accessChecker = AccessChecker.getInstance(env.getConfiguration(), zk); + } else { + accessChecker = null; + } } @Override @@ -393,5 +407,92 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver { groupAdminServer.removeServers(clearedServer); } - ///////////////////////////////////////////////////////////////////////////// + + @Override + public void preMoveServersAndTables(ObserverContext ctx, + Set
servers, Set tables, String targetGroup) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "moveServersAndTables", Action.ADMIN); + } + } + + @Override + public void preMoveServers(ObserverContext ctx, + Set
servers, String targetGroup) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "moveServers", Action.ADMIN); + } + } + + @Override + public void preMoveTables(ObserverContext ctx, + Set tables, String targetGroup) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "moveTables", Action.ADMIN); + } + } + + @Override + public void preAddRSGroup(ObserverContext ctx, + String name) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "addRSGroup", Action.ADMIN); + } + } + + @Override + public void preRemoveRSGroup(ObserverContext ctx, + String name) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "removeRSGroup", Action.ADMIN); + } + } + + @Override + public void preBalanceRSGroup(ObserverContext ctx, + String groupName) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "balanceRSGroup", Action.ADMIN); + } + } + + @Override + public void preRemoveServers(ObserverContext ctx, + Set
servers) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "removeServers", Action.ADMIN); + } + } + + @Override + public void preListRSGroup(ObserverContext ctx) + throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "listRSGroup", Action.ADMIN); + } + } + + @Override + public void preGetRSGroupInfo(ObserverContext ctx, + String groupName) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "getRSGroup", Action.ADMIN); + } + } + + @Override + public void preGetRSGroupInfoOfTable(ObserverContext ctx, + TableName tableName) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "getRSGroupInfoOfTable", Action.ADMIN); + } + } + + @Override + public void preGetRSGroupOfServer(ObserverContext ctx, + Address hostPort) throws IOException { + if (aclEnabled) { + accessChecker.requirePermission(ctx, "getRSGroupOfServer", Action.ADMIN); + } + } } diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java index 45421e325b..c6e8a007ba 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java @@ -67,15 +67,32 @@ public class RSGroupAdminServer implements RSGroupAdmin { @Override public RSGroupInfo getRSGroupInfo(String groupName) throws IOException { - return rsGroupInfoManager.getRSGroup(groupName); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().preGetRSGroupInfo(groupName); + } + RSGroupInfo rsGroupInfo = rsGroupInfoManager.getRSGroup(groupName); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().postGetRSGroupInfo(groupName, rsGroupInfo); + } + return rsGroupInfo; + } @Override public RSGroupInfo getRSGroupInfoOfTable(TableName tableName) throws IOException { + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().preGetRSGroupInfoOfTable(tableName); + } + // We are reading across two Maps in the below with out synchronizing across // them; should be safe most of the time. String groupName = rsGroupInfoManager.getRSGroupOfTable(tableName); - return groupName == null? null: rsGroupInfoManager.getRSGroup(groupName); + RSGroupInfo rsGroupInfo = groupName == null? + null: rsGroupInfoManager.getRSGroup(groupName); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().postGetRSGroupInfoOfTable(tableName, rsGroupInfo); + } + return rsGroupInfo; } private void checkOnlineServersOnly(Set
servers) throws ConstraintException { @@ -536,12 +553,26 @@ public class RSGroupAdminServer implements RSGroupAdmin { @Override public List listRSGroups() throws IOException { - return rsGroupInfoManager.listRSGroups(); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().preListRSGroup(); + } + List rsGroupInfos = rsGroupInfoManager.listRSGroups(); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().postListRSGroup(rsGroupInfos); + } + return rsGroupInfos; } @Override public RSGroupInfo getRSGroupOfServer(Address hostPort) throws IOException { - return rsGroupInfoManager.getRSGroupOfServer(hostPort); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().preGetRSGroupOfServer(hostPort); + } + RSGroupInfo rsGroupInfo = rsGroupInfoManager.getRSGroupOfServer(hostPort); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().postGetRSGroupOfServer(hostPort, rsGroupInfo); + } + return rsGroupInfo; } @Override diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index 6ef5504ad9..44a90ba56b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -37,6 +37,7 @@ import org.apache.hadoop.hbase.master.RegionPlan; 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.rsgroup.RSGroupInfo; import org.apache.yetus.audience.InterfaceAudience; import org.apache.yetus.audience.InterfaceStability; @@ -1117,6 +1118,76 @@ public interface MasterObserver { Set
servers) throws IOException {} /** + * Called before list rsgroup + * @param ctx the environment to interact with the framework and master + */ + default void preListRSGroup( + final ObserverContext ctx) throws IOException {} + + /** + * Called after list rsgroup + * @param ctx the environment to interact with the framework and master + * @param rsGroupInfos list of RSGroupInfo or an empty list if there is no group + */ + default void postListRSGroup(final ObserverContext ctx, + final List rsGroupInfos) throws IOException {} + + /** + * Called before get rsgroup info for given group name + * @param ctx the environment to interact with the framework and master + * @param groupName the given group name + */ + default void preGetRSGroupInfo(final ObserverContext ctx, + final String groupName) throws IOException {} + + /** + * Called after get rsgroup info for given group name + * @param ctx the environment to interact with the framework and master + * @param groupName the given group name + * @param rsGroupInfo RSGroupInfo to which the given group belongs + * or null if the group is not found + */ + default void postGetRSGroupInfo(final ObserverContext ctx, + final String groupName, final RSGroupInfo rsGroupInfo) throws IOException {} + + /** + * Called before get rsgroup info for given table name + * @param ctx the environment to interact with the framework and master + * @param tableName the given table name + */ + default void preGetRSGroupInfoOfTable(final ObserverContext ctx, + final TableName tableName) throws IOException {} + + /** + * Called after get rsgroup info for given table name + * @param ctx the environment to interact with the framework and master + * @param tableName the given table name + * @param rsGroupInfo RSGroupInfo to which the given table belongs + * or null if the given table not belongs to any group + */ + default void postGetRSGroupInfoOfTable(final ObserverContext ctx, + final TableName tableName, final RSGroupInfo rsGroupInfo) throws IOException {} + + /** + * Called before get rsgroup info for given server + * @param ctx the environment to interact with the framework and master + * @param hostPort the given server + */ + default void preGetRSGroupOfServer(final ObserverContext ctx, + final Address hostPort) throws IOException {} + + /** + * Called after get rsgroup info for given server + * @param ctx the environment to interact with the framework and master + * @param hostPort the given server + * @param rsGroupInfo RSGroupInfo to which the given server belongs + * or null if the given server not belongs to any group + */ + default void postGetRSGroupOfServer(final ObserverContext ctx, + final Address hostPort, final RSGroupInfo rsGroupInfo) throws IOException {} + + + /** * Called before add a replication peer * @param ctx the environment to interact with the framework and master * @param peerId a short name that identifies the peer diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index bc262290fc..a7e5926f06 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -59,6 +59,7 @@ import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.quotas.GlobalQuotaSettings; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; +import org.apache.hadoop.hbase.rsgroup.RSGroupInfo; import org.apache.hadoop.hbase.security.User; import org.apache.yetus.audience.InterfaceAudience; @@ -1426,6 +1427,94 @@ public class MasterCoprocessorHost }); } + public void preListRSGroup() throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.preListRSGroup(this); + } + } + }); + } + + public void postListRSGroup(List rsGroupInfos) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.postListRSGroup(this, rsGroupInfos); + } + } + }); + } + + public void preGetRSGroupInfo(String groupName) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.preGetRSGroupInfo(this, groupName); + } + } + }); + } + + public void postGetRSGroupInfo(String groupName, RSGroupInfo rsGroupInfo) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.postGetRSGroupInfo(this, groupName, rsGroupInfo); + } + } + }); + } + + public void preGetRSGroupInfoOfTable(TableName tableName) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.preGetRSGroupInfoOfTable(this, tableName); + } + } + }); + } + + public void postGetRSGroupInfoOfTable(TableName tableName, RSGroupInfo rsGroupInfo) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.postGetRSGroupInfoOfTable(this, tableName, rsGroupInfo); + } + } + }); + } + + public void preGetRSGroupOfServer(Address hostPort) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.preGetRSGroupOfServer(this, hostPort); + } + } + }); + } + + public void postGetRSGroupOfServer(Address hostPort, RSGroupInfo rsGroupInfo) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + if(((MasterEnvironment)getEnvironment()).supportGroupCPs) { + observer.postGetRSGroupOfServer(this, hostPort, rsGroupInfo); + } + } + }); + } + public void preAddReplicationPeer(final String peerId, final ReplicationPeerConfig peerConfig) throws IOException { execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index 3e2f0efdeb..6241d18c48 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -83,6 +83,7 @@ import org.apache.hadoop.hbase.replication.ReplicationException; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.security.access.AccessChecker; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.visibility.VisibilityController; import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; @@ -1799,7 +1800,7 @@ public class MasterRpcServices extends RSRpcServices // A coprocessor that implements AccessControlService can provide AUTHORIZATION and // CELL_AUTHORIZATION if (master.cpHost != null && hasAccessControlServiceCoprocessor(master.cpHost)) { - if (AccessController.isAuthorizationSupported(master.getConfiguration())) { + if (AccessChecker.isAuthorizationSupported(master.getConfiguration())) { capabilities.add(SecurityCapabilitiesResponse.Capability.AUTHORIZATION); } if (AccessController.isCellAuthorizationSupported(master.getConfiguration())) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessChecker.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessChecker.java new file mode 100644 index 0000000000..630d9800fd --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessChecker.java @@ -0,0 +1,410 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.hadoop.hbase.security.access; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.DoNotRetryIOException; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.ipc.RpcServer; +import org.apache.hadoop.hbase.security.AccessDeniedException; +import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.security.UserProvider; +import org.apache.hadoop.hbase.zookeeper.ZKWatcher; +import org.apache.yetus.audience.InterfaceAudience; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +@InterfaceAudience.Public +public class AccessChecker { + private static final Log AUDITLOG = + LogFactory.getLog("SecurityLogger." + AccessChecker.class.getName()); + private static AccessChecker INSTANCE; + private TableAuthManager authManager; + /** + * if we are active, usually true, only not true if "hbase.security.authorization" + * has been set to false in site configuration + */ + private boolean authorizationEnabled; + + public static boolean isAuthorizationSupported(Configuration conf) { + return conf.getBoolean(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, true); + } + + /** Provider for mapping principal names to Users */ + private UserProvider userProvider; + + /** + * Constructor with existing configuration + * + * @param conf Existing configuration to use + * @param zkw reference to the {@link ZKWatcher} + * @return the AccessChecker instance + */ + public synchronized static AccessChecker getInstance(Configuration conf, + ZKWatcher zkw) throws RuntimeException { + return new AccessChecker(conf, zkw); + } + + private AccessChecker(final Configuration conf, final ZKWatcher zk) + throws RuntimeException { + // If zk is null or IOException while obtaining auth manager, + // throw RuntimeException so that the coprocessor is unloaded. + if (zk != null) { + try { + this.authManager = TableAuthManager.getOrCreate(zk, conf); + } catch (IOException ioe) { + throw new RuntimeException("Error obtaining AccessChecker", ioe); + } + } else { + throw new RuntimeException("Error obtaining AccessChecker, zk found null."); + } + authorizationEnabled = isAuthorizationSupported(conf); + // set the user-provider. + this.userProvider = UserProvider.instantiate(conf); + } + + public TableAuthManager getAuthManager() { + return authManager; + } + + /** + * 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 + */ + public void requireAccess(User user, String request, TableName tableName, + Permission.Action... permissions) throws IOException { + AuthResult result = null; + + for (Permission.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()); + } + } + + public void requireAccess(ObserverContext ctx, String request, TableName tableName, + Permission.Action... permissions) throws IOException { + requireAccess(getActiveUser(ctx), request, tableName, permissions); + } + + /** + * Authorizes that the current user has global privileges for the given action. + * + * @param perm The action being requested + * @throws IOException if obtaining the current user fails + * @throws AccessDeniedException if authorization is denied + */ + public void requirePermission(User user, String request, Permission.Action perm) + throws IOException { + requireGlobalPermission(user, request, perm, null, null); + } + + public void requirePermission(ObserverContext ctx, String request, + Permission.Action perm) throws IOException { + requirePermission(getActiveUser(ctx), request, perm); + } + + /** + * 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(User user, String request, + Permission.Action perm, TableName tableName, + Map> familyMap)throws IOException { + 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() + ")"); + } + } + } + + public void requireGlobalPermission(ObserverContext ctx, String request, + Permission.Action perm, TableName tableName, + Map> familyMap) throws IOException { + requireGlobalPermission(getActiveUser(ctx), request, perm, tableName, familyMap); + } + + /** + * 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 + */ + public void requireGlobalPermission(User user, String request, Permission.Action perm, + String namespace) throws IOException { + 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() + ")"); + } + } + } + + public void requireGlobalPermission(ObserverContext ctx, String request, + Permission.Action perm, String namespace) throws IOException { + requireGlobalPermission(getActiveUser(ctx), request, perm, namespace); + } + + /** + * Checks that the user has the given global or namespace permission. + * + * @param namespace + * @param permissions Actions being requested + */ + public void requireNamespacePermission(User user, String request, String namespace, + Permission.Action... permissions) throws IOException { + AuthResult result = null; + + for (Permission.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()); + } + } + public void requireNamespacePermission(ObserverContext ctx, String request, String namespace, + Permission.Action... permissions) throws IOException { + requireNamespacePermission(getActiveUser(ctx), request, namespace, permissions); + } + + + /** + * Checks that the user has the given global or namespace permission. + * + * @param namespace + * @param permissions Actions being requested + */ + public void requireNamespacePermission(User user, String request, String namespace, + TableName tableName, Map> familyMap, + Permission.Action... permissions) throws IOException { + AuthResult result = null; + + for (Permission.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()); + } + } + + public void requireNamespacePermission(ObserverContext ctx, String request, String namespace, + TableName tableName, Map> familyMap, + Permission.Action... permissions) throws IOException { + requireNamespacePermission(getActiveUser(ctx), request, namespace, tableName, familyMap, permissions); + } + + /** + * 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 + */ + public void requirePermission(User user, String request, TableName tableName, byte[] family, + byte[] qualifier, Permission.Action... permissions) throws IOException { + AuthResult result = null; + + for (Permission.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()); + } + } + + public void requirePermission(ObserverContext ctx, String request, TableName tableName, byte[] family, + byte[] qualifier, Permission.Action... permissions) throws IOException { + requirePermission(getActiveUser(ctx), request, tableName, family, qualifier, permissions); + } + + /** + * 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 + */ + public void requireTablePermission(User user, String request, + TableName tableName,byte[] family, byte[] qualifier, + Permission.Action... permissions) throws IOException { + AuthResult result = null; + + for (Permission.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()); + } + } + + public void requireTablePermission(ObserverContext ctx, String request, + TableName tableName,byte[] family, byte[] qualifier, + Permission.Action... permissions) throws IOException { + requireTablePermission(getActiveUser(ctx), request, tableName, family, qualifier, permissions); + } + + + public void checkLockPermissions(User user, String namespace, + TableName tableName, RegionInfo[] regionInfos, String reason) + throws IOException { + if (namespace != null && !namespace.isEmpty()) { + requireNamespacePermission(user, reason, namespace, Permission.Action.ADMIN, Permission.Action.CREATE); + } else if (tableName != null || (regionInfos != null && regionInfos.length > 0)) { + // So, either a table or regions op. If latter, check perms ons table. + TableName tn = tableName != null? tableName: regionInfos[0].getTable(); + requireTablePermission(user, reason, tn, null, null, + Permission.Action.ADMIN, Permission.Action.CREATE); + } else { + throw new DoNotRetryIOException("Invalid lock level when requesting permissions."); + } + } + + public void checkLockPermissions(ObserverContext ctx, String namespace, + TableName tableName, RegionInfo[] regionInfos, String reason) + throws IOException { + checkLockPermissions(getActiveUser(ctx), namespace, tableName, regionInfos, reason); + } + + public static void logResult(AuthResult result) { + if (AUDITLOG.isTraceEnabled()) { + AUDITLOG.trace("Access " + (result.isAllowed() ? "allowed" : "denied") + " for user " + ( + result.getUser() != null ? + result.getUser().getShortName() : + "UNKNOWN") + "; reason: " + result.getReason() + "; remote address: " + + RpcServer.getRemoteAddress().map(InetAddress::toString).orElse("") + "; request: " + result + .getRequest() + "; context: " + result.toContextString()); + } + } + + /** + * Returns the active user to which authorization checks should be applied. + * If we are in the context of an RPC call, the remote user is used, + * otherwise the currently logged in user is used. + */ + public User getActiveUser(ObserverContext ctx) throws IOException { + // for non-rpc handling, fallback to system user + Optional optionalUser = ctx.getCaller(); + if (optionalUser.isPresent()) { + return optionalUser.get(); + } + return userProvider.getCurrent(); + } +} \ No newline at end of file diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index 0f9d8a5a8f..aad6c6b0a5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -24,7 +24,6 @@ import com.google.protobuf.RpcController; import com.google.protobuf.Service; import java.io.IOException; -import java.net.InetAddress; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Collection; @@ -188,10 +187,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, private static final String TAG_CHECK_PASSED = "tag_check_passed"; private static final byte[] TRUE = Bytes.toBytes(true); - TableAuthManager authManager = null; + private AccessChecker accessChecker = null; /** flags if we are running on a region of the _acl_ table */ - boolean aclRegion = false; + private boolean aclRegion = false; /** defined only for Endpoint implementation, so it can have way to access region services */ @@ -208,17 +207,17 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, /** if we are active, usually true, only not true if "hbase.security.authorization" has been set to false in site configuration */ - boolean authorizationEnabled; + private boolean authorizationEnabled; /** if we are able to support cell ACLs */ - boolean cellFeaturesEnabled; + private boolean cellFeaturesEnabled; /** if we should check EXEC permissions */ - boolean shouldCheckExecPermission; + private boolean shouldCheckExecPermission; /** if we should terminate access checks early as soon as table or CF grants allow access; pre-0.98 compatible behavior */ - boolean compatibleEarlyTermination; + private boolean compatibleEarlyTermination; /** if we have been successfully initialized */ private volatile boolean initialized = false; @@ -226,12 +225,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, /** if the ACL table is available, only relevant in the master */ private volatile boolean aclTabAvailable = false; - public static boolean isAuthorizationSupported(Configuration conf) { - return conf.getBoolean(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, true); - } - public static boolean isCellAuthorizationSupported(Configuration conf) { - return isAuthorizationSupported(conf) && + return AccessChecker.isAuthorizationSupported(conf) && (HFile.getFormatVersion(conf) >= HFile.MIN_FORMAT_VERSION_WITH_TAGS); } @@ -240,10 +235,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } public TableAuthManager getAuthManager() { - return authManager; + return accessChecker.getAuthManager(); } - void initialize(RegionCoprocessorEnvironment e) throws IOException { + private void initialize(RegionCoprocessorEnvironment e) throws IOException { final Region region = e.getRegion(); Configuration conf = e.getConfiguration(); Map> tables = @@ -255,7 +250,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, byte[] entry = t.getKey(); ListMultimap perms = t.getValue(); byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, conf); - this.authManager.getZKPermissionWatcher().writeToZookeeper(entry, serialized); + getAuthManager().getZKPermissionWatcher().writeToZookeeper(entry, serialized); } initialized = true; } @@ -265,7 +260,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, * znodes. This is called to synchronize ACL changes following {@code _acl_} * table updates. */ - void updateACL(RegionCoprocessorEnvironment e, + private void updateACL(RegionCoprocessorEnvironment e, final Map> familyMap) { Set entries = new TreeSet<>(Bytes.BYTES_RAWCOMPARATOR); for (Map.Entry> f : familyMap.entrySet()) { @@ -276,7 +271,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } } } - ZKPermissionWatcher zkw = this.authManager.getZKPermissionWatcher(); + ZKPermissionWatcher zkw = getAuthManager().getZKPermissionWatcher(); Configuration conf = regionEnv.getConfiguration(); byte [] currentEntry = null; // TODO: Here we are already on the ACL region. (And it is single @@ -314,7 +309,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, * the request * @return an authorization result */ - AuthResult permissionGranted(String request, User user, Action permRequest, + private AuthResult permissionGranted(String request, User user, Action permRequest, RegionCoprocessorEnvironment e, Map> families) { RegionInfo hri = e.getRegion().getRegionInfo(); @@ -335,7 +330,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } // 2. check for the table-level, if successful we can short-circuit - if (authManager.authorize(user, tableName, (byte[])null, permRequest)) { + if (getAuthManager().authorize(user, tableName, (byte[])null, permRequest)) { return AuthResult.allow(request, "Table permission granted", user, permRequest, tableName, families); } @@ -345,7 +340,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // all families must pass for (Map.Entry> family : families.entrySet()) { // a) check for family level access - if (authManager.authorize(user, tableName, family.getKey(), + if (getAuthManager().authorize(user, tableName, family.getKey(), permRequest)) { continue; // family-level permission overrides per-qualifier } @@ -356,7 +351,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // for each qualifier of the family Set familySet = (Set)family.getValue(); for (byte[] qualifier : familySet) { - if (!authManager.authorize(user, tableName, family.getKey(), + if (!getAuthManager().authorize(user, tableName, family.getKey(), qualifier, permRequest)) { return AuthResult.deny(request, "Failed qualifier check", user, permRequest, tableName, makeFamilyMap(family.getKey(), qualifier)); @@ -365,7 +360,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } else if (family.getValue() instanceof List) { // List List cellList = (List)family.getValue(); for (Cell cell : cellList) { - if (!authManager.authorize(user, tableName, family.getKey(), + if (!getAuthManager().authorize(user, tableName, family.getKey(), CellUtil.cloneQualifier(cell), permRequest)) { return AuthResult.deny(request, "Failed qualifier check", user, permRequest, tableName, makeFamilyMap(family.getKey(), CellUtil.cloneQualifier(cell))); @@ -400,7 +395,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, * @param actions the desired actions * @return an authorization result */ - AuthResult permissionGranted(OpType opType, User user, RegionCoprocessorEnvironment e, + private AuthResult permissionGranted(OpType opType, User user, RegionCoprocessorEnvironment e, Map> families, Action... actions) { AuthResult result = null; for (Action action: actions) { @@ -412,243 +407,6 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, return result; } - private void logResult(AuthResult result) { - if (AUDITLOG.isTraceEnabled()) { - AUDITLOG.trace("Access " + (result.isAllowed() ? "allowed" : "denied") + " for user " + - (result.getUser() != null ? result.getUser().getShortName() : "UNKNOWN") + "; reason: " + - result.getReason() + "; remote address: " + - RpcServer.getRemoteAddress().map(InetAddress::toString).orElse("") + "; request: " + - result.getRequest() + "; context: " + result.toContextString()); - } - } - - /** - * Returns the active user to which authorization checks should be applied. - * If we are in the context of an RPC call, the remote user is used, - * otherwise the currently logged in user is used. - */ - private User getActiveUser(ObserverContext ctx) throws IOException { - // for non-rpc handling, fallback to system user - Optional optionalUser = ctx.getCaller(); - User user; - if (optionalUser.isPresent()) { - return optionalUser.get(); - } - return userProvider.getCurrent(); - } - - /** - * 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(User user, String request, TableName tableName, byte[] family, - byte[] qualifier, Action... permissions) throws IOException { - 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(User user, String request, TableName tableName, byte[] family, - byte[] qualifier, Action... permissions) throws IOException { - 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()); - } - } - - /** - * 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(User user, String request, TableName tableName, - Action... permissions) throws IOException { - 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()); - } - } - - /** - * Authorizes that the current user has global privileges for the given action. - * @param perm The action being requested - * @throws IOException if obtaining the current user fails - * @throws AccessDeniedException if authorization is denied - */ - private void requirePermission(User user, String request, Action perm) throws IOException { - requireGlobalPermission(user, request, perm, null, null); - } - - /** - * 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(User user, String request, Action perm, TableName tableName, - Map> familyMap) throws IOException { - 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(User user, String request, Action perm, - String namespace) throws IOException { - 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(User user, String request, String namespace, - Action... permissions) throws IOException { - 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(User user, String request, String namespace, - TableName tableName, Map> familyMap, - Action... permissions) - throws IOException { - 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()); - } - } - /** * Returns true if the current user is allowed the given action * over at least one of the column qualifiers in the given column families. @@ -671,13 +429,13 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, familyMap.entrySet()) { if (family.getValue() != null && !family.getValue().isEmpty()) { for (byte[] qualifier : family.getValue()) { - if (authManager.matchPermission(user, tableName, + if (getAuthManager().matchPermission(user, tableName, family.getKey(), qualifier, perm)) { return true; } } } else { - if (authManager.matchPermission(user, tableName, family.getKey(), + if (getAuthManager().matchPermission(user, tableName, family.getKey(), perm)) { return true; } @@ -867,7 +625,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, foundColumn = true; for (Action action: actions) { // Are there permissions for this user for the cell? - if (!authManager.authorize(user, getTableName(e), cell, action)) { + if (!getAuthManager().authorize(user, getTableName(e), cell, action)) { // We can stop if the cell ACL denies access return false; } @@ -942,7 +700,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, CompoundConfiguration conf = new CompoundConfiguration(); conf.add(env.getConfiguration()); - authorizationEnabled = isAuthorizationSupported(conf); + authorizationEnabled = AccessChecker.isAuthorizationSupported(conf); if (!authorizationEnabled) { LOG.warn("The AccessController has been loaded with authorization checks disabled."); } @@ -982,26 +740,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // set the user-provider. this.userProvider = UserProvider.instantiate(env.getConfiguration()); - - // If zk is null or IOException while obtaining auth manager, - // throw RuntimeException so that the coprocessor is unloaded. - if (zk != null) { - try { - this.authManager = TableAuthManager.getOrCreate(zk, env.getConfiguration()); - } catch (IOException ioe) { - throw new RuntimeException("Error obtaining TableAuthManager", ioe); - } - } else { - throw new RuntimeException("Error obtaining TableAuthManager, zk found null."); - } - + accessChecker = AccessChecker.getInstance(env.getConfiguration(), zk); tableAcls = new MapMaker().weakValues().makeMap(); } @Override public void stop(CoprocessorEnvironment env) { - if (this.authManager != null) { - TableAuthManager.release(authManager); + if (accessChecker != null) { + TableAuthManager.release(getAuthManager()); } } @@ -1047,7 +793,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (byte[] family: families) { familyMap.put(family, null); } - requireNamespacePermission(getActiveUser(c), "createTable", + accessChecker.requireNamespacePermission(c, "createTable", desc.getTableName().getNamespaceAsString(), desc.getTableName(), familyMap, Action.CREATE); } @@ -1082,7 +828,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, String owner = desc.getOwnerString(); // default the table owner to current user, if not specified. if (owner == null) - owner = getActiveUser(c).getShortName(); + owner = accessChecker.getActiveUser(c).getShortName(); final UserPermission userperm = new UserPermission(Bytes.toBytes(owner), desc.getTableName(), null, Action.values()); // switch to the real hbase master user for doing the RPC on the ACL table @@ -1104,8 +850,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preDeleteTable(ObserverContext c, TableName tableName) throws IOException { - requirePermission(getActiveUser(c), "deleteTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "deleteTable", + tableName, null, null, Action.ADMIN, Action.CREATE); } @Override @@ -1122,14 +868,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, return null; } }); - this.authManager.getZKPermissionWatcher().deleteTableACLNode(tableName); + getAuthManager().getZKPermissionWatcher().deleteTableACLNode(tableName); } @Override public void preTruncateTable(ObserverContext c, final TableName tableName) throws IOException { - requirePermission(getActiveUser(c), "truncateTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "truncateTable", + tableName, null, null, Action.ADMIN, Action.CREATE); final Configuration conf = c.getEnvironment().getConfiguration(); User.runAsLoginUser(new PrivilegedExceptionAction() { @@ -1170,8 +916,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void preModifyTable(ObserverContext c, TableName tableName, TableDescriptor htd) throws IOException { // TODO: potentially check if this is a add/modify/delete column operation - requirePermission(getActiveUser(c), "modifyTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "modifyTable", + tableName, null, null, Action.ADMIN, Action.CREATE); } @Override @@ -1180,7 +926,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, 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(c).getShortName(); + accessChecker.getActiveUser(c).getShortName(); User.runAsLoginUser(new PrivilegedExceptionAction() { @Override public Void run() throws Exception { @@ -1198,8 +944,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preEnableTable(ObserverContext c, TableName tableName) throws IOException { - requirePermission(getActiveUser(c), "enableTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "enableTable", + tableName, null, null, Action.ADMIN, Action.CREATE); } @Override @@ -1213,14 +959,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, throw new AccessDeniedException("Not allowed to disable " + AccessControlLists.ACL_TABLE_NAME + " table with AccessController installed"); } - requirePermission(getActiveUser(c), "disableTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "disableTable", + tableName, null, null, Action.ADMIN, Action.CREATE); } @Override public void preAbortProcedure(ObserverContext ctx, final long procId) throws IOException { - requirePermission(getActiveUser(ctx), "abortProcedure", Action.ADMIN); + accessChecker.requirePermission(ctx, "abortProcedure", Action.ADMIN); } @Override @@ -1232,74 +978,73 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preGetProcedures(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "getProcedure", Action.ADMIN); + accessChecker.requirePermission(ctx, "getProcedure", Action.ADMIN); } @Override public void preGetLocks(ObserverContext ctx) throws IOException { - User user = getActiveUser(ctx); - requirePermission(user, "getLocks", Action.ADMIN); + User user = accessChecker.getActiveUser(ctx); + accessChecker.requirePermission(user, "getLocks", Action.ADMIN); } @Override public void preMove(ObserverContext c, RegionInfo region, ServerName srcServer, ServerName destServer) throws IOException { - requirePermission(getActiveUser(c), "move", region.getTable(), null, null, Action.ADMIN); + accessChecker.requirePermission(c, "move", + region.getTable(), null, null, Action.ADMIN); } @Override public void preAssign(ObserverContext c, RegionInfo regionInfo) throws IOException { - requirePermission(getActiveUser(c), "assign", regionInfo.getTable(), null, null, Action.ADMIN); + accessChecker.requirePermission(c, "assign", + regionInfo.getTable(), null, null, Action.ADMIN); } @Override public void preUnassign(ObserverContext c, RegionInfo regionInfo, boolean force) throws IOException { - requirePermission(getActiveUser(c), "unassign", regionInfo.getTable(), null, null, Action.ADMIN); + accessChecker.requirePermission(c, "unassign", + regionInfo.getTable(), null, null, Action.ADMIN); } @Override public void preRegionOffline(ObserverContext c, RegionInfo regionInfo) throws IOException { - requirePermission(getActiveUser(c), "regionOffline", regionInfo.getTable(), null, null, - Action.ADMIN); + accessChecker.requirePermission(c, "regionOffline", + regionInfo.getTable(), null, null, Action.ADMIN); } @Override public void preSetSplitOrMergeEnabled(final ObserverContext ctx, final boolean newValue, final MasterSwitchType switchType) throws IOException { - requirePermission(getActiveUser(ctx), "setSplitOrMergeEnabled", Action.ADMIN); - } - - @Override - public void postSetSplitOrMergeEnabled(final ObserverContext ctx, - final boolean newValue, final MasterSwitchType switchType) throws IOException { + accessChecker.requirePermission(ctx, "setSplitOrMergeEnabled", + Action.ADMIN); } @Override public void preBalance(ObserverContext c) throws IOException { - requirePermission(getActiveUser(c), "balance", Action.ADMIN); + accessChecker.requirePermission(c, "balance", Action.ADMIN); } @Override public void preBalanceSwitch(ObserverContext c, boolean newValue) throws IOException { - requirePermission(getActiveUser(c), "balanceSwitch", Action.ADMIN); + accessChecker.requirePermission(c, "balanceSwitch", Action.ADMIN); } @Override public void preShutdown(ObserverContext c) throws IOException { - requirePermission(getActiveUser(c), "shutdown", Action.ADMIN); + accessChecker.requirePermission(c, "shutdown", Action.ADMIN); } @Override public void preStopMaster(ObserverContext c) throws IOException { - requirePermission(getActiveUser(c), "stopMaster", Action.ADMIN); + accessChecker.requirePermission(c, "stopMaster", Action.ADMIN); } @Override @@ -1337,21 +1082,21 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void preSnapshot(final ObserverContext ctx, final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor) throws IOException { - requirePermission(getActiveUser(ctx), "snapshot " + snapshot.getName(), hTableDescriptor.getTableName(), null, null, - Permission.Action.ADMIN); + accessChecker.requirePermission(ctx, "snapshot " + snapshot.getName(), + hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN); } @Override public void preListSnapshot(ObserverContext ctx, final SnapshotDescription snapshot) throws IOException { - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, user)) { // list it, if user is the owner of snapshot AuthResult result = AuthResult.allow("listSnapshot " + snapshot.getName(), "Snapshot owner check allowed", user, null, null, null); - logResult(result); + AccessChecker.logResult(result); } else { - requirePermission(user, "listSnapshot " + snapshot.getName(), Action.ADMIN); + accessChecker.requirePermission(user, "listSnapshot " + snapshot.getName(), Action.ADMIN); } } @@ -1359,15 +1104,15 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void preCloneSnapshot(final ObserverContext ctx, final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor) throws IOException { - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, user) && hTableDescriptor.getTableName().getNameAsString().equals(snapshot.getTable())) { // Snapshot owner is allowed to create a table with the same name as the snapshot he took AuthResult result = AuthResult.allow("cloneSnapshot " + snapshot.getName(), "Snapshot owner check allowed", user, null, hTableDescriptor.getTableName(), null); - logResult(result); + AccessChecker.logResult(result); } else { - requirePermission(user, "cloneSnapshot " + snapshot.getName(), Action.ADMIN); + accessChecker.requirePermission(user, "cloneSnapshot " + snapshot.getName(), Action.ADMIN); } } @@ -1375,39 +1120,41 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void preRestoreSnapshot(final ObserverContext ctx, final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor) throws IOException { - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, user)) { - requirePermission(user, "restoreSnapshot " + snapshot.getName(), hTableDescriptor.getTableName(), null, null, - Permission.Action.ADMIN); + accessChecker.requirePermission(user, "restoreSnapshot " + snapshot.getName(), + hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN); } else { - requirePermission(user, "restoreSnapshot " + snapshot.getName(), Action.ADMIN); + accessChecker.requirePermission(user, "restoreSnapshot " + snapshot.getName(), Action.ADMIN); } } @Override public void preDeleteSnapshot(final ObserverContext ctx, final SnapshotDescription snapshot) throws IOException { - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, user)) { // Snapshot owner is allowed to delete the snapshot AuthResult result = AuthResult.allow("deleteSnapshot " + snapshot.getName(), "Snapshot owner check allowed", user, null, null, null); - logResult(result); + AccessChecker.logResult(result); } else { - requirePermission(user, "deleteSnapshot " + snapshot.getName(), Action.ADMIN); + accessChecker.requirePermission(user, "deleteSnapshot " + snapshot.getName(), Action.ADMIN); } } @Override public void preCreateNamespace(ObserverContext ctx, NamespaceDescriptor ns) throws IOException { - requireGlobalPermission(getActiveUser(ctx), "createNamespace", Action.ADMIN, ns.getName()); + accessChecker.requireGlobalPermission(ctx, "createNamespace", + Action.ADMIN, ns.getName()); } @Override public void preDeleteNamespace(ObserverContext ctx, String namespace) throws IOException { - requireGlobalPermission(getActiveUser(ctx), "deleteNamespace", Action.ADMIN, namespace); + accessChecker.requireGlobalPermission(ctx, "deleteNamespace", + Action.ADMIN, namespace); } @Override @@ -1424,7 +1171,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, return null; } }); - this.authManager.getZKPermissionWatcher().deleteNamespaceACLNode(namespace); + getAuthManager().getZKPermissionWatcher().deleteNamespaceACLNode(namespace); LOG.info(namespace + " entry deleted in " + AccessControlLists.ACL_TABLE_NAME + " table."); } @@ -1433,13 +1180,15 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, NamespaceDescriptor ns) throws IOException { // We require only global permission so that // a user with NS admin cannot altering namespace configurations. i.e. namespace quota - requireGlobalPermission(getActiveUser(ctx), "modifyNamespace", Action.ADMIN, ns.getName()); + accessChecker.requireGlobalPermission(ctx, "modifyNamespace", + Action.ADMIN, ns.getName()); } @Override public void preGetNamespaceDescriptor(ObserverContext ctx, String namespace) throws IOException { - requireNamespacePermission(getActiveUser(ctx), "getNamespaceDescriptor", namespace, Action.ADMIN); + accessChecker.requireNamespacePermission(ctx, "getNamespaceDescriptor", + namespace, Action.ADMIN); } @Override @@ -1448,11 +1197,12 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // Retains only those which passes authorization checks, as the checks weren't done as part // of preGetTableDescriptors. Iterator itr = descriptors.iterator(); - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); while (itr.hasNext()) { NamespaceDescriptor desc = itr.next(); try { - requireNamespacePermission(user, "listNamespaces", desc.getName(), Action.ADMIN); + accessChecker.requireNamespacePermission(user, "listNamespaces", + desc.getName(), Action.ADMIN); } catch (AccessDeniedException e) { itr.remove(); } @@ -1462,8 +1212,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preTableFlush(final ObserverContext ctx, final TableName tableName) throws IOException { - requirePermission(getActiveUser(ctx), "flushTable", tableName, null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(ctx, "flushTable", tableName, + null, null, Action.ADMIN, Action.CREATE); } @Override @@ -1471,29 +1221,33 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, final ObserverContext ctx, final TableName tableName, final byte[] splitRow) throws IOException { - requirePermission(getActiveUser(ctx), "split", tableName, null, null, Action.ADMIN); + accessChecker.requirePermission(ctx, "split", tableName, + null, null, Action.ADMIN); } @Override - public void preClearDeadServers(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "clearDeadServers", Action.ADMIN); + public void preClearDeadServers(ObserverContext ctx) + throws IOException { + accessChecker.requirePermission(ctx, "clearDeadServers", Action.ADMIN); } @Override public void preDecommissionRegionServers(ObserverContext ctx, List servers, boolean offload) throws IOException { - requirePermission(getActiveUser(ctx), "decommissionRegionServers", Action.ADMIN); + accessChecker.requirePermission(ctx, "decommissionRegionServers", Action.ADMIN); } @Override - public void preListDecommissionedRegionServers(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "listDecommissionedRegionServers", Action.ADMIN); + public void preListDecommissionedRegionServers(ObserverContext ctx) + throws IOException { + accessChecker.requirePermission(ctx, "listDecommissionedRegionServers", + Action.ADMIN); } @Override public void preRecommissionRegionServer(ObserverContext ctx, ServerName server, List encodedRegionNames) throws IOException { - requirePermission(getActiveUser(ctx), "recommissionRegionServers", Action.ADMIN); + accessChecker.requirePermission(ctx, "recommissionRegionServers", Action.ADMIN); } /* ---- RegionObserver implementation ---- */ @@ -1508,9 +1262,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } else { RegionInfo regionInfo = region.getRegionInfo(); if (regionInfo.getTable().isSystemTable()) { - checkSystemOrSuperUser(getActiveUser(c)); + checkSystemOrSuperUser(accessChecker.getActiveUser(c)); } else { - requirePermission(getActiveUser(c), "preOpen", Action.ADMIN); + accessChecker.requirePermission(c, "preOpen", Action.ADMIN); } } } @@ -1540,16 +1294,16 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preFlush(ObserverContext c, FlushLifeCycleTracker tracker) throws IOException { - requirePermission(getActiveUser(c), "flush", getTableName(c.getEnvironment()), null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "flush", getTableName(c.getEnvironment()), + null, null, Action.ADMIN, Action.CREATE); } @Override public InternalScanner preCompact(ObserverContext c, Store store, InternalScanner scanner, ScanType scanType, CompactionLifeCycleTracker tracker, CompactionRequest request) throws IOException { - requirePermission(getActiveUser(c), "compact", getTableName(c.getEnvironment()), null, null, - Action.ADMIN, Action.CREATE); + accessChecker.requirePermission(c, "compact", getTableName(c.getEnvironment()), + null, null, Action.ADMIN, Action.CREATE); return scanner; } @@ -1560,7 +1314,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, if (filter != null && filter instanceof AccessControlFilter) { return; } - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = null; switch (opType) { @@ -1596,7 +1350,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, authResult.setReason("Access allowed with filter"); // Only wrap the filter if we are enforcing authorizations if (authorizationEnabled) { - Filter ourFilter = new AccessControlFilter(authManager, user, table, + Filter ourFilter = new AccessControlFilter(getAuthManager(), user, table, AccessControlFilter.Strategy.CHECK_TABLE_AND_CF_ONLY, cfVsMaxVersions); // wrap any existing filter @@ -1626,7 +1380,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, authResult.setReason("Access allowed with filter"); // Only wrap the filter if we are enforcing authorizations if (authorizationEnabled) { - Filter ourFilter = new AccessControlFilter(authManager, user, table, + Filter ourFilter = new AccessControlFilter(getAuthManager(), user, table, AccessControlFilter.Strategy.CHECK_CELL_DEFAULT, cfVsMaxVersions); // wrap any existing filter if (filter != null) { @@ -1648,7 +1402,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions for user '" + (user != null ? user.getShortName() : "null") @@ -1673,7 +1427,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void prePut(final ObserverContext c, final Put put, final WALEdit edit, final Durability durability) throws IOException { - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); checkForReservedTagPresence(user, put); // Require WRITE permission to the table, CF, or top visible value, if any. @@ -1684,8 +1438,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // security policy over time without requiring expensive updates. RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = put.getFamilyCellMap(); - AuthResult authResult = permissionGranted(OpType.PUT, user, env, families, Action.WRITE); - logResult(authResult); + AuthResult authResult = permissionGranted(OpType.PUT, + user, env, families, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { put.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -1728,9 +1483,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // by a tombstone already) then we have to disallow this operation. RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = delete.getFamilyCellMap(); - User user = getActiveUser(c); - AuthResult authResult = permissionGranted(OpType.DELETE, user, env, families, Action.WRITE); - logResult(authResult); + User user = accessChecker.getActiveUser(c); + AuthResult authResult = permissionGranted(OpType.DELETE, + user, env, families, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { delete.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -1746,7 +1502,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, MiniBatchOperationInProgress miniBatchOp) throws IOException { if (cellFeaturesEnabled && !compatibleEarlyTermination) { TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); for (int i = 0; i < miniBatchOp.size(); i++) { Mutation m = miniBatchOp.getOperation(i); if (m.getAttribute(CHECK_COVERING_PERM) != null) { @@ -1768,7 +1524,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, authResult = AuthResult.deny(opType.toString(), "Covering cell set", user, Action.WRITE, table, m.getFamilyCellMap()); } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); @@ -1793,15 +1549,15 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, final CompareOperator op, final ByteArrayComparable comparator, final Put put, final boolean result) throws IOException { - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); checkForReservedTagPresence(user, put); // Require READ and WRITE permissions on the table, CF, and KV to update RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = makeFamilyMap(family, qualifier); - AuthResult authResult = permissionGranted(OpType.CHECK_AND_PUT, user, env, families, - Action.READ, Action.WRITE); - logResult(authResult); + AuthResult authResult = permissionGranted(OpType.CHECK_AND_PUT, + user, env, families, Action.READ, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { put.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -1824,26 +1580,25 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public boolean preCheckAndPutAfterRowLock(final ObserverContext c, - final byte[] row, final byte[] family, final byte[] qualifier, - final CompareOperator opp, final ByteArrayComparable comparator, final Put put, - final boolean result) - throws IOException { + final byte[] row, final byte[] family, final byte[] qualifier, + final CompareOperator opp, 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> families = makeFamilyMap(family, qualifier); AuthResult authResult = null; - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); if (checkCoveringPermission(user, OpType.CHECK_AND_PUT, c.getEnvironment(), row, families, HConstants.LATEST_TIMESTAMP, Action.READ)) { - authResult = AuthResult.allow(OpType.CHECK_AND_PUT.toString(), "Covering cell set", - user, Action.READ, table, families); + authResult = AuthResult.allow(OpType.CHECK_AND_PUT.toString(), + "Covering cell set", user, Action.READ, table, families); } else { - authResult = AuthResult.deny(OpType.CHECK_AND_PUT.toString(), "Covering cell set", - user, Action.READ, table, families); + authResult = AuthResult.deny(OpType.CHECK_AND_PUT.toString(), + "Covering cell set", user, Action.READ, table, families); } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); } @@ -1866,10 +1621,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // by the delete RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = makeFamilyMap(family, qualifier); - User user = getActiveUser(c); - AuthResult authResult = permissionGranted(OpType.CHECK_AND_DELETE, user, env, families, - Action.READ, Action.WRITE); - logResult(authResult); + User user = accessChecker.getActiveUser(c); + AuthResult authResult = permissionGranted( + OpType.CHECK_AND_DELETE, user, env, families, Action.READ, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { delete.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -1883,8 +1638,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public boolean preCheckAndDeleteAfterRowLock( - final ObserverContext c, final byte[] row, final byte[] family, - final byte[] qualifier, final CompareOperator op, + final ObserverContext c, final byte[] row, + final byte[] family, final byte[] qualifier, final CompareOperator op, final ByteArrayComparable comparator, final Delete delete, final boolean result) throws IOException { if (delete.getAttribute(CHECK_COVERING_PERM) != null) { @@ -1893,16 +1648,16 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); Map> families = makeFamilyMap(family, qualifier); AuthResult authResult = null; - User user = getActiveUser(c); - if (checkCoveringPermission(user, OpType.CHECK_AND_DELETE, c.getEnvironment(), row, families, - HConstants.LATEST_TIMESTAMP, Action.READ)) { - authResult = AuthResult.allow(OpType.CHECK_AND_DELETE.toString(), "Covering cell set", - user, Action.READ, table, families); + User user = accessChecker.getActiveUser(c); + if (checkCoveringPermission(user, OpType.CHECK_AND_DELETE, c.getEnvironment(), + row, families, HConstants.LATEST_TIMESTAMP, Action.READ)) { + authResult = AuthResult.allow(OpType.CHECK_AND_DELETE.toString(), + "Covering cell set", user, Action.READ, table, families); } else { - authResult = AuthResult.deny(OpType.CHECK_AND_DELETE.toString(), "Covering cell set", - user, Action.READ, table, families); + authResult = AuthResult.deny(OpType.CHECK_AND_DELETE.toString(), + "Covering cell set", user, Action.READ, table, families); } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); } @@ -1913,14 +1668,15 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public Result preAppend(ObserverContext c, Append append) throws IOException { - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); checkForReservedTagPresence(user, append); // Require WRITE permission to the table, CF, and the KV to be appended RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = append.getFamilyCellMap(); - AuthResult authResult = permissionGranted(OpType.APPEND, user, env, families, Action.WRITE); - logResult(authResult); + AuthResult authResult = permissionGranted(OpType.APPEND, user, + env, families, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { append.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -1950,16 +1706,16 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // perm check TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); AuthResult authResult = null; - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); if (checkCoveringPermission(user, OpType.APPEND, c.getEnvironment(), append.getRow(), append.getFamilyCellMap(), append.getTimeRange().getMax(), Action.WRITE)) { - authResult = AuthResult.allow(OpType.APPEND.toString(), "Covering cell set", - user, Action.WRITE, table, append.getFamilyCellMap()); + authResult = AuthResult.allow(OpType.APPEND.toString(), + "Covering cell set", user, Action.WRITE, table, append.getFamilyCellMap()); } else { - authResult = AuthResult.deny(OpType.APPEND.toString(), "Covering cell set", - user, Action.WRITE, table, append.getFamilyCellMap()); + authResult = AuthResult.deny(OpType.APPEND.toString(), + "Covering cell set", user, Action.WRITE, table, append.getFamilyCellMap()); } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); @@ -1972,16 +1728,16 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public Result preIncrement(final ObserverContext c, final Increment increment) throws IOException { - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); checkForReservedTagPresence(user, increment); // Require WRITE permission to the table, CF, and the KV to be replaced by // the incremented value RegionCoprocessorEnvironment env = c.getEnvironment(); Map> families = increment.getFamilyCellMap(); - AuthResult authResult = permissionGranted(OpType.INCREMENT, user, env, families, - Action.WRITE); - logResult(authResult); + AuthResult authResult = permissionGranted(OpType.INCREMENT, + user, env, families, Action.WRITE); + AccessChecker.logResult(authResult); if (!authResult.isAllowed()) { if (cellFeaturesEnabled && !compatibleEarlyTermination) { increment.setAttribute(CHECK_COVERING_PERM, TRUE); @@ -2011,16 +1767,16 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // perm check TableName table = c.getEnvironment().getRegion().getRegionInfo().getTable(); AuthResult authResult = null; - User user = getActiveUser(c); - if (checkCoveringPermission(user, OpType.INCREMENT, c.getEnvironment(), increment.getRow(), - increment.getFamilyCellMap(), increment.getTimeRange().getMax(), Action.WRITE)) { + User user = accessChecker.getActiveUser(c); + if (checkCoveringPermission(user, OpType.INCREMENT, c.getEnvironment(), + increment.getRow(), increment.getFamilyCellMap(), increment.getTimeRange().getMax(), Action.WRITE)) { authResult = AuthResult.allow(OpType.INCREMENT.toString(), "Covering cell set", user, Action.WRITE, table, increment.getFamilyCellMap()); } else { authResult = AuthResult.deny(OpType.INCREMENT.toString(), "Covering cell set", user, Action.WRITE, table, increment.getFamilyCellMap()); } - logResult(authResult); + AccessChecker.logResult(authResult); if (authorizationEnabled && !authResult.isAllowed()) { throw new AccessDeniedException("Insufficient permissions " + authResult.toContextString()); @@ -2095,7 +1851,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public RegionScanner postScannerOpen(final ObserverContext c, final Scan scan, final RegionScanner s) throws IOException { - User user = getActiveUser(c); + User user = accessChecker.getActiveUser(c); if (user != null && user.getShortName() != null) { // store reference to scanner owner for later checks scannerOwners.put(s, user.getShortName()); @@ -2156,9 +1912,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preBulkLoadHFile(ObserverContext ctx, List> familyPaths) throws IOException { - User user = getActiveUser(ctx); + User user = accessChecker.getActiveUser(ctx); for(Pair el : familyPaths) { - requirePermission(user, "preBulkLoadHFile", + accessChecker.requirePermission(user, "preBulkLoadHFile", ctx.getEnvironment().getRegion().getTableDescriptor().getTableName(), el.getFirst(), null, @@ -2175,7 +1931,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void prePrepareBulkLoad(ObserverContext ctx) throws IOException { - requireAccess(getActiveUser(ctx), "prePrepareBulkLoad", + accessChecker.requireAccess(ctx, "prePrepareBulkLoad", ctx.getEnvironment().getRegion().getTableDescriptor().getTableName(), Action.CREATE); } @@ -2188,7 +1944,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preCleanupBulkLoad(ObserverContext ctx) throws IOException { - requireAccess(getActiveUser(ctx), "preCleanupBulkLoad", + accessChecker.requireAccess(ctx, "preCleanupBulkLoad", ctx.getEnvironment().getRegion().getTableDescriptor().getTableName(), Action.CREATE); } @@ -2200,7 +1956,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // Don't intercept calls to our own AccessControlService, we check for // appropriate permissions in the service handlers if (shouldCheckExecPermission && !(service instanceof AccessControlService)) { - requirePermission(getActiveUser(ctx), + accessChecker.requirePermission(ctx, "invoke(" + service.getDescriptorForType().getName() + "." + methodName + ")", getTableName(ctx.getEnvironment()), null, null, Action.EXEC); @@ -2217,8 +1973,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void grant(RpcController controller, - AccessControlProtos.GrantRequest request, - RpcCallback done) { + AccessControlProtos.GrantRequest request, + RpcCallback done) { final UserPermission perm = AccessControlUtil.toUserPermission(request.getUserPermission()); AccessControlProtos.GrantResponse response = null; try { @@ -2235,11 +1991,11 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, switch(request.getUserPermission().getPermission().getType()) { case Global : case Table : - requirePermission(caller, "grant", perm.getTableName(), + accessChecker.requirePermission(caller, "grant", perm.getTableName(), perm.getFamily(), perm.getQualifier(), Action.ADMIN); break; case Namespace : - requireNamespacePermission(caller, "grant", perm.getNamespace(), Action.ADMIN); + accessChecker.requireNamespacePermission(caller, "grant", perm.getNamespace(), Action.ADMIN); break; } @@ -2274,8 +2030,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void revoke(RpcController controller, - AccessControlProtos.RevokeRequest request, - RpcCallback done) { + AccessControlProtos.RevokeRequest request, + RpcCallback done) { final UserPermission perm = AccessControlUtil.toUserPermission(request.getUserPermission()); AccessControlProtos.RevokeResponse response = null; try { @@ -2292,11 +2048,11 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, switch(request.getUserPermission().getPermission().getType()) { case Global : case Table : - requirePermission(caller, "revoke", perm.getTableName(), perm.getFamily(), + accessChecker.requirePermission(caller, "revoke", perm.getTableName(), perm.getFamily(), perm.getQualifier(), Action.ADMIN); break; case Namespace : - requireNamespacePermission(caller, "revoke", perm.getNamespace(), Action.ADMIN); + accessChecker.requireNamespacePermission(caller, "revoke", perm.getNamespace(), Action.ADMIN); break; } @@ -2330,8 +2086,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void getUserPermissions(RpcController controller, - AccessControlProtos.GetUserPermissionsRequest request, - RpcCallback done) { + AccessControlProtos.GetUserPermissionsRequest request, + RpcCallback done) { AccessControlProtos.GetUserPermissionsResponse response = null; try { // only allowed to be called on _acl_ region @@ -2345,7 +2101,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, if (request.getType() == AccessControlProtos.Permission.Type.Table) { final TableName table = request.hasTableName() ? ProtobufUtil.toTableName(request.getTableName()) : null; - requirePermission(caller, "userPermissions", table, null, null, Action.ADMIN); + accessChecker.requirePermission(caller, "userPermissions", table, null, null, Action.ADMIN); perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { @Override public List run() throws Exception { @@ -2354,7 +2110,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, }); } else if (request.getType() == AccessControlProtos.Permission.Type.Namespace) { final String namespace = request.getNamespaceName().toStringUtf8(); - requireNamespacePermission(caller, "userPermissions", namespace, Action.ADMIN); + accessChecker.requireNamespacePermission(caller, "userPermissions", namespace, Action.ADMIN); perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { @Override public List run() throws Exception { @@ -2363,7 +2119,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } }); } else { - requirePermission(caller, "userPermissions", Action.ADMIN); + accessChecker.requirePermission(caller, "userPermissions", Action.ADMIN); perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { @Override public List run() throws Exception { @@ -2428,7 +2184,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, AuthResult result = permissionGranted("checkPermissions", user, action, regionEnv, familyMap); - logResult(result); + AccessChecker.logResult(result); if (!result.isAllowed()) { // Even if passive we need to throw an exception here, we support checking // effective permissions, so throw unconditionally @@ -2443,14 +2199,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (Action action : permission.getActions()) { AuthResult result; - if (authManager.authorize(user, action)) { + if (getAuthManager().authorize(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); } - logResult(result); + AccessChecker.logResult(result); if (!result.isAllowed()) { // Even if passive we need to throw an exception here, we support checking // effective permissions, so throw unconditionally @@ -2490,7 +2246,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preClose(ObserverContext c, boolean abortRequested) throws IOException { - requirePermission(getActiveUser(c), "preClose", Action.ADMIN); + accessChecker.requirePermission(c, "preClose", Action.ADMIN); } private void checkSystemOrSuperUser(User activeUser) throws IOException { @@ -2508,7 +2264,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void preStopRegionServer( ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "preStopRegionServer", Action.ADMIN); + accessChecker.requirePermission(ctx, "preStopRegionServer", Action.ADMIN); } private Map> makeFamilyMap(byte[] family, @@ -2538,7 +2294,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (TableName tableName: tableNamesList) { // Skip checks for a table that does not exist if (!admin.tableExists(tableName)) continue; - requirePermission(getActiveUser(ctx), "getTableDescriptors", tableName, null, null, + accessChecker.requirePermission(ctx, "getTableDescriptors", tableName, null, null, Action.ADMIN, Action.CREATE); } } @@ -2560,7 +2316,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, while (itr.hasNext()) { TableDescriptor htd = itr.next(); try { - requirePermission(getActiveUser(ctx), "getTableDescriptors", htd.getTableName(), null, null, + accessChecker.requirePermission(ctx, "getTableDescriptors", htd.getTableName(), null, null, Action.ADMIN, Action.CREATE); } catch (AccessDeniedException e) { itr.remove(); @@ -2576,7 +2332,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, while (itr.hasNext()) { TableDescriptor htd = itr.next(); try { - requireAccess(getActiveUser(ctx), "getTableNames", htd.getTableName(), Action.values()); + accessChecker.requireAccess(ctx, "getTableNames", htd.getTableName(), Action.values()); } catch (AccessDeniedException e) { itr.remove(); } @@ -2586,14 +2342,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preMergeRegions(final ObserverContext ctx, final RegionInfo[] regionsToMerge) throws IOException { - requirePermission(getActiveUser(ctx), "mergeRegions", regionsToMerge[0].getTable(), null, null, + accessChecker.requirePermission(ctx, "mergeRegions", regionsToMerge[0].getTable(), null, null, Action.ADMIN); } @Override public void preRollWALWriterRequest(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "preRollLogWriterRequest", Permission.Action.ADMIN); + accessChecker.requirePermission(ctx, "preRollLogWriterRequest", Permission.Action.ADMIN); } @Override @@ -2603,33 +2359,33 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preSetUserQuota(final ObserverContext ctx, final String userName, final GlobalQuotaSettings quotas) throws IOException { - requirePermission(getActiveUser(ctx), "setUserQuota", Action.ADMIN); + accessChecker.requirePermission(ctx, "setUserQuota", Action.ADMIN); } @Override public void preSetUserQuota(final ObserverContext ctx, final String userName, final TableName tableName, final GlobalQuotaSettings quotas) throws IOException { - requirePermission(getActiveUser(ctx), "setUserTableQuota", tableName, null, null, Action.ADMIN); + accessChecker.requirePermission(ctx, "setUserTableQuota", tableName, null, null, Action.ADMIN); } @Override public void preSetUserQuota(final ObserverContext ctx, final String userName, final String namespace, final GlobalQuotaSettings quotas) throws IOException { - requirePermission(getActiveUser(ctx), "setUserNamespaceQuota", Action.ADMIN); + accessChecker.requirePermission(ctx, "setUserNamespaceQuota", Action.ADMIN); } @Override public void preSetTableQuota(final ObserverContext ctx, final TableName tableName, final GlobalQuotaSettings quotas) throws IOException { - requirePermission(getActiveUser(ctx), "setTableQuota", tableName, null, null, Action.ADMIN); + accessChecker.requirePermission(ctx, "setTableQuota", tableName, null, null, Action.ADMIN); } @Override public void preSetNamespaceQuota(final ObserverContext ctx, final String namespace, final GlobalQuotaSettings quotas) throws IOException { - requirePermission(getActiveUser(ctx), "setNamespaceQuota", Action.ADMIN); + accessChecker.requirePermission(ctx, "setNamespaceQuota", Action.ADMIN); } @Override @@ -2641,98 +2397,98 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preReplicateLogEntries(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "replicateLogEntries", Action.WRITE); + accessChecker.requirePermission(ctx, "replicateLogEntries", Action.WRITE); } @Override public void preClearCompactionQueues(ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "preClearCompactionQueues", Permission.Action.ADMIN); + accessChecker.requirePermission(ctx, "preClearCompactionQueues", Permission.Action.ADMIN); } @Override public void preMoveServersAndTables(ObserverContext ctx, Set
servers, Set tables, String targetGroup) throws IOException { - requirePermission(getActiveUser(ctx), "moveServersAndTables", Action.ADMIN); + accessChecker.requirePermission(ctx, "moveServersAndTables", Action.ADMIN); } @Override public void preMoveServers(ObserverContext ctx, Set
servers, String targetGroup) throws IOException { - requirePermission(getActiveUser(ctx), "moveServers", Action.ADMIN); + accessChecker.requirePermission(ctx, "moveServers", Action.ADMIN); } @Override public void preMoveTables(ObserverContext ctx, Set tables, String targetGroup) throws IOException { - requirePermission(getActiveUser(ctx), "moveTables", Action.ADMIN); + accessChecker.requirePermission(ctx, "moveTables", Action.ADMIN); } @Override public void preAddRSGroup(ObserverContext ctx, String name) throws IOException { - requirePermission(getActiveUser(ctx), "addRSGroup", Action.ADMIN); + accessChecker.requirePermission(ctx, "addRSGroup", Action.ADMIN); } @Override public void preRemoveRSGroup(ObserverContext ctx, String name) throws IOException { - requirePermission(getActiveUser(ctx), "removeRSGroup", Action.ADMIN); + accessChecker.requirePermission(ctx, "removeRSGroup", Action.ADMIN); } @Override public void preBalanceRSGroup(ObserverContext ctx, String groupName) throws IOException { - requirePermission(getActiveUser(ctx), "balanceRSGroup", Action.ADMIN); + accessChecker.requirePermission(ctx, "balanceRSGroup", Action.ADMIN); } @Override public void preRemoveServers(ObserverContext ctx, Set
servers) throws IOException { - requirePermission(getActiveUser(ctx), "removeServers", Action.ADMIN); + accessChecker.requirePermission(ctx, "removeServers", Action.ADMIN); } @Override public void preAddReplicationPeer(final ObserverContext ctx, String peerId, ReplicationPeerConfig peerConfig) throws IOException { - requirePermission(getActiveUser(ctx), "addReplicationPeer", Action.ADMIN); + accessChecker.requirePermission(ctx, "addReplicationPeer", Action.ADMIN); } @Override public void preRemoveReplicationPeer(final ObserverContext ctx, String peerId) throws IOException { - requirePermission(getActiveUser(ctx), "removeReplicationPeer", Action.ADMIN); + accessChecker.requirePermission(ctx, "removeReplicationPeer", Action.ADMIN); } @Override public void preEnableReplicationPeer(final ObserverContext ctx, String peerId) throws IOException { - requirePermission(getActiveUser(ctx), "enableReplicationPeer", Action.ADMIN); + accessChecker.requirePermission(ctx, "enableReplicationPeer", Action.ADMIN); } @Override public void preDisableReplicationPeer(final ObserverContext ctx, String peerId) throws IOException { - requirePermission(getActiveUser(ctx), "disableReplicationPeer", Action.ADMIN); + accessChecker.requirePermission(ctx, "disableReplicationPeer", Action.ADMIN); } @Override public void preGetReplicationPeerConfig(final ObserverContext ctx, String peerId) throws IOException { - requirePermission(getActiveUser(ctx), "getReplicationPeerConfig", Action.ADMIN); + accessChecker.requirePermission(ctx, "getReplicationPeerConfig", Action.ADMIN); } @Override public void preUpdateReplicationPeerConfig( final ObserverContext ctx, String peerId, ReplicationPeerConfig peerConfig) throws IOException { - requirePermission(getActiveUser(ctx), "updateReplicationPeerConfig", Action.ADMIN); + accessChecker.requirePermission(ctx, "updateReplicationPeerConfig", Action.ADMIN); } @Override public void preListReplicationPeers(final ObserverContext ctx, String regex) throws IOException { - requirePermission(getActiveUser(ctx), "listReplicationPeers", Action.ADMIN); + accessChecker.requirePermission(ctx, "listReplicationPeers", Action.ADMIN); } @Override @@ -2742,33 +2498,18 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // There are operations in the CREATE and ADMIN domain which may require lock, READ // or WRITE. So for any lock request, we check for these two perms irrespective of lock type. String reason = String.format("Description=%s", description); - checkLockPermissions(getActiveUser(ctx), namespace, tableName, regionInfos, reason); + accessChecker.checkLockPermissions(ctx, namespace, tableName, regionInfos, reason); } @Override public void preLockHeartbeat(ObserverContext ctx, TableName tableName, String description) throws IOException { - checkLockPermissions(getActiveUser(ctx), null, tableName, null, description); + accessChecker.checkLockPermissions(ctx, null, tableName, null, description); } @Override public void preGetClusterStatus(final ObserverContext ctx) throws IOException { - requirePermission(getActiveUser(ctx), "getClusterStatus", Action.ADMIN); - } - - private void checkLockPermissions(User user, String namespace, - TableName tableName, RegionInfo[] regionInfos, String reason) - throws IOException { - if (namespace != null && !namespace.isEmpty()) { - requireNamespacePermission(user, reason, namespace, Action.ADMIN, Action.CREATE); - } else if (tableName != null || (regionInfos != null && regionInfos.length > 0)) { - // So, either a table or regions op. If latter, check perms ons table. - TableName tn = tableName != null? tableName: regionInfos[0].getTable(); - requireTablePermission(user, reason, tn, null, null, - Action.ADMIN, Action.CREATE); - } else { - throw new DoNotRetryIOException("Invalid lock level when requesting permissions."); - } + accessChecker.requirePermission(ctx, "getClusterStatus", Action.ADMIN); } } diff --git a/src/main/asciidoc/_chapters/appendix_acl_matrix.adoc b/src/main/asciidoc/_chapters/appendix_acl_matrix.adoc index 0c99b1f361..626b2668a7 100644 --- a/src/main/asciidoc/_chapters/appendix_acl_matrix.adoc +++ b/src/main/asciidoc/_chapters/appendix_acl_matrix.adoc @@ -164,6 +164,17 @@ In case the table goes out of date, the unit tests which check for accuracy of p | | mergeRegions | superuser\|global(A) | | rollWALWriterRequest | superuser\|global(A) | | replicateLogEntries | superuser\|global(W) +|RSGroup |addRSGroup |superuser\|global(A) +| |balanceRSGroup |superuser\|global(A) +| |getRSGroupInfo |superuser\|global(A) +| |getRSGroupInfoOfTable|superuser\|global(A) +| |getRSGroupOfServer |superuser\|global(A) +| |listRSGroups |superuser\|global(A) +| |moveServers |superuser\|global(A) +| |moveServersAndTables |superuser\|global(A) +| |moveTables |superuser\|global(A) +| |removeRSGroup |superuser\|global(A) +| |removeServers |superuser\|global(A) |=== :numbered: -- 2.13.0.windows.1