HBASE-20185 Fix ACL check for MasterRpcServices#execProcedure

This commit is contained in:
Apekshit Sharma 2018-03-13 17:13:56 +05:30
parent b06aec4450
commit ad425e8603
7 changed files with 49 additions and 15 deletions

View File

@ -57,6 +57,7 @@ import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils; import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
import org.apache.hadoop.hbase.ipc.PriorityFunction; import org.apache.hadoop.hbase.ipc.PriorityFunction;
import org.apache.hadoop.hbase.ipc.QosPriority; import org.apache.hadoop.hbase.ipc.QosPriority;
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.ipc.RpcServer.BlockingServiceAndInterface; import org.apache.hadoop.hbase.ipc.RpcServer.BlockingServiceAndInterface;
import org.apache.hadoop.hbase.ipc.RpcServerFactory; import org.apache.hadoop.hbase.ipc.RpcServerFactory;
import org.apache.hadoop.hbase.ipc.RpcServerInterface; import org.apache.hadoop.hbase.ipc.RpcServerInterface;
@ -831,8 +832,8 @@ public class MasterRpcServices extends RSRpcServices
@Override @Override
public ExecProcedureResponse execProcedure(RpcController controller, public ExecProcedureResponse execProcedure(RpcController controller,
ExecProcedureRequest request) throws ServiceException { ExecProcedureRequest request) throws ServiceException {
rpcPreCheck("execProcedure");
try { try {
master.checkInitialized();
ProcedureDescription desc = request.getProcedure(); ProcedureDescription desc = request.getProcedure();
MasterProcedureManager mpm = master.getMasterProcedureManagerHost().getProcedureManager( MasterProcedureManager mpm = master.getMasterProcedureManagerHost().getProcedureManager(
desc.getSignature()); desc.getSignature());
@ -841,6 +842,7 @@ public class MasterRpcServices extends RSRpcServices
+ desc.getSignature())); + desc.getSignature()));
} }
LOG.info(master.getClientIdAuditPrefix() + " procedure request for: " + desc.getSignature()); LOG.info(master.getClientIdAuditPrefix() + " procedure request for: " + desc.getSignature());
mpm.checkPermissions(desc, accessChecker, RpcServer.getRequestUser().orElse(null));
mpm.execProcedure(desc); mpm.execProcedure(desc);
// send back the max amount of time the client should wait for the procedure // send back the max amount of time the client should wait for the procedure
// to complete // to complete

View File

@ -63,6 +63,7 @@ import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator;
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
import org.apache.hadoop.hbase.security.AccessDeniedException; import org.apache.hadoop.hbase.security.AccessDeniedException;
import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException; import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
@ -1149,6 +1150,13 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
takeSnapshot(toSnapshotDescription(desc)); takeSnapshot(toSnapshotDescription(desc));
} }
@Override
public void checkPermissions(ProcedureDescription desc, AccessChecker accessChecker, User user)
throws IOException {
// Done by AccessController as part of preSnapshot coprocessor hook (legacy code path).
// In future, when we AC is removed for good, that check should be moved here.
}
@Override @Override
public boolean isProcedureDone(ProcedureDescription desc) throws IOException { public boolean isProcedureDone(ProcedureDescription desc) throws IOException {
return isSnapshotDone(toSnapshotDescription(desc)); return isSnapshotDone(toSnapshotDescription(desc));

View File

@ -19,6 +19,8 @@ package org.apache.hadoop.hbase.procedure;
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.yetus.audience.InterfaceAudience; import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability; import org.apache.yetus.audience.InterfaceStability;
import org.apache.hadoop.hbase.Stoppable; import org.apache.hadoop.hbase.Stoppable;
@ -34,28 +36,26 @@ import org.apache.zookeeper.KeeperException;
* *
* To implement a custom globally barriered procedure, user needs to extend two classes: * To implement a custom globally barriered procedure, user needs to extend two classes:
* {@link MasterProcedureManager} and {@link RegionServerProcedureManager}. Implementation of * {@link MasterProcedureManager} and {@link RegionServerProcedureManager}. Implementation of
* {@link MasterProcedureManager} is loaded into {@link org.apache.hadoop.hbase.master.HMaster} * {@link MasterProcedureManager} is loaded into {@link org.apache.hadoop.hbase.master.HMaster}
* process via configuration parameter 'hbase.procedure.master.classes', while implementation of * process via configuration parameter 'hbase.procedure.master.classes', while implementation of
* {@link RegionServerProcedureManager} is loaded into * {@link RegionServerProcedureManager} is loaded into
* {@link org.apache.hadoop.hbase.regionserver.HRegionServer} process via * {@link org.apache.hadoop.hbase.regionserver.HRegionServer} process via
* configuration parameter 'hbase.procedure.regionserver.classes'. * configuration parameter 'hbase.procedure.regionserver.classes'.
* *
* An example of globally barriered procedure implementation is * An example of globally barriered procedure implementation is
* {@link org.apache.hadoop.hbase.master.snapshot.SnapshotManager} and * {@link org.apache.hadoop.hbase.master.snapshot.SnapshotManager} and
* {@link org.apache.hadoop.hbase.regionserver.snapshot.RegionServerSnapshotManager}. * {@link org.apache.hadoop.hbase.regionserver.snapshot.RegionServerSnapshotManager}.
* *
* A globally barriered procedure is identified by its signature (usually it is the name of the * A globally barriered procedure is identified by its signature (usually it is the name of the
* procedure znode). During the initialization phase, the initialize methods are called by both * procedure znode). During the initialization phase, the initialize methods are called by both
* {@link org.apache.hadoop.hbase.master.HMaster} * {@link org.apache.hadoop.hbase.master.HMaster}
* and {@link org.apache.hadoop.hbase.regionserver.HRegionServer} which create the procedure znode * and {@link org.apache.hadoop.hbase.regionserver.HRegionServer} which create the procedure znode
* and register the listeners. A procedure can be triggered by its signature and an instant name * and register the listeners. A procedure can be triggered by its signature and an instant name
* (encapsulated in a {@link ProcedureDescription} object). When the servers are shutdown, * (encapsulated in a {@link ProcedureDescription} object). When the servers are shutdown,
* the stop methods on both classes are called to clean up the data associated with the procedure. * the stop methods on both classes are called to clean up the data associated with the procedure.
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
@InterfaceStability.Evolving public abstract class MasterProcedureManager extends ProcedureManager implements Stoppable {
public abstract class MasterProcedureManager extends ProcedureManager implements
Stoppable {
/** /**
* Initialize a globally barriered procedure for master. * Initialize a globally barriered procedure for master.
* *
@ -73,9 +73,7 @@ public abstract class MasterProcedureManager extends ProcedureManager implements
* @param desc Procedure description * @param desc Procedure description
* @throws IOException * @throws IOException
*/ */
public void execProcedure(ProcedureDescription desc) throws IOException { public void execProcedure(ProcedureDescription desc) throws IOException {}
}
/** /**
* Execute a distributed procedure on cluster with return data. * Execute a distributed procedure on cluster with return data.
@ -89,6 +87,13 @@ public abstract class MasterProcedureManager extends ProcedureManager implements
return null; return null;
} }
/**
* Check for required permissions before executing the procedure.
* @throws IOException if permissions requirements are not met.
*/
public abstract void checkPermissions(ProcedureDescription desc, AccessChecker accessChecker,
User user) throws IOException;
/** /**
* Check if the procedure is finished successfully * Check if the procedure is finished successfully
* *

View File

@ -41,6 +41,9 @@ import org.apache.hadoop.hbase.procedure.Procedure;
import org.apache.hadoop.hbase.procedure.ProcedureCoordinator; import org.apache.hadoop.hbase.procedure.ProcedureCoordinator;
import org.apache.hadoop.hbase.procedure.ProcedureCoordinatorRpcs; import org.apache.hadoop.hbase.procedure.ProcedureCoordinatorRpcs;
import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator; import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
import org.apache.yetus.audience.InterfaceAudience; import org.apache.yetus.audience.InterfaceAudience;
@ -181,6 +184,13 @@ public class MasterFlushTableProcedureManager extends MasterProcedureManager {
monitor.rethrowException(); monitor.rethrowException();
} }
@Override
public void checkPermissions(ProcedureDescription desc, AccessChecker accessChecker, User user)
throws IOException {
// Done by AccessController as part of preTableFlush coprocessor hook (legacy code path).
// In future, when we AC is removed for good, that check should be moved here.
}
@Override @Override
public synchronized boolean isProcedureDone(ProcedureDescription desc) throws IOException { public synchronized boolean isProcedureDone(ProcedureDescription desc) throws IOException {
// Procedure instance name is the table name. // Procedure instance name is the table name.

View File

@ -331,7 +331,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
// Initialized in start() since AccessChecker needs ZKWatcher which is created by HRegionServer // Initialized in start() since AccessChecker needs ZKWatcher which is created by HRegionServer
// after RSRpcServices constructor and before start() is called. // after RSRpcServices constructor and before start() is called.
// Initialized only if authorization is enabled, else remains null. // Initialized only if authorization is enabled, else remains null.
private AccessChecker accessChecker; protected AccessChecker accessChecker;
/** /**
* Services launched in RSRpcServices. By default they are on but you can use the below * Services launched in RSRpcServices. By default they are on but you can use the below

View File

@ -1136,6 +1136,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx, public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor) final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
throws IOException { throws IOException {
// Move this ACL check to SnapshotManager#checkPermissions as part of AC deprecation.
requirePermission(ctx, "snapshot " + snapshot.getName(), requirePermission(ctx, "snapshot " + snapshot.getName(),
hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN); hTableDescriptor.getTableName(), null, null, Permission.Action.ADMIN);
} }
@ -1266,6 +1267,8 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
@Override @Override
public void preTableFlush(final ObserverContext<MasterCoprocessorEnvironment> ctx, public void preTableFlush(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final TableName tableName) throws IOException { final TableName tableName) throws IOException {
// Move this ACL check to MasterFlushTableProcedureManager#checkPermissions as part of AC
// deprecation.
requirePermission(ctx, "flushTable", tableName, requirePermission(ctx, "flushTable", tableName,
null, null, Action.ADMIN, Action.CREATE); null, null, Action.ADMIN, Action.CREATE);
} }

View File

@ -29,6 +29,8 @@ import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.MetricsMaster; import org.apache.hadoop.hbase.master.MetricsMaster;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ProcedureDescription; import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ProcedureDescription;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -113,6 +115,10 @@ public class SimpleMasterProcedureManager extends MasterProcedureManager {
return returnData.values().iterator().next(); return returnData.values().iterator().next();
} }
@Override
public void checkPermissions(ProcedureDescription desc, AccessChecker accessChecker, User user)
throws IOException {}
@Override @Override
public boolean isProcedureDone(ProcedureDescription desc) throws IOException { public boolean isProcedureDone(ProcedureDescription desc) throws IOException {
return done; return done;