HBASE-12674 Add permission check to getNamespaceDescriptor()

This commit is contained in:
Matteo Bertozzi 2014-12-11 16:55:42 +00:00
parent 75cf81aae5
commit c4aee2e283
8 changed files with 139 additions and 5 deletions

View File

@ -157,6 +157,16 @@ public abstract class BaseMasterAndRegionObserver extends BaseRegionObserver
NamespaceDescriptor ns) throws IOException {
}
@Override
public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
String namespace) throws IOException {
}
@Override
public void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
NamespaceDescriptor ns) throws IOException {
}
@Override
public void preListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
List<NamespaceDescriptor> descriptors) throws IOException {

View File

@ -150,6 +150,16 @@ public class BaseMasterObserver implements MasterObserver {
public void postModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx, NamespaceDescriptor ns) throws IOException {
}
@Override
public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
String namespace) throws IOException {
}
@Override
public void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
NamespaceDescriptor ns) throws IOException {
}
@Override
public void preListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
List<NamespaceDescriptor> descriptors) throws IOException {

View File

@ -788,6 +788,24 @@ public interface MasterObserver extends Coprocessor {
void postModifyNamespace(final ObserverContext<MasterCoprocessorEnvironment> ctx,
NamespaceDescriptor ns) throws IOException;
/**
* Called before a getNamespaceDescriptor request has been processed.
* @param ctx the environment to interact with the framework and master
* @param namespace the name of the namespace
* @throws IOException
*/
void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
String namespace) throws IOException;
/**
* Called after a getNamespaceDescriptor request has been processed.
* @param ctx the environment to interact with the framework and master
* @param ns the NamespaceDescriptor
* @throws IOException
*/
void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
NamespaceDescriptor ns) throws IOException;
/**
* Called before a listNamespaceDescriptors request has been processed.
* @param ctx the environment to interact with the framework and master

View File

@ -1248,7 +1248,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
}
String namespace = hTableDescriptor.getTableName().getNamespaceAsString();
getNamespaceDescriptor(namespace); // ensure namespace exists
ensureNamespaceExists(namespace);
HRegionInfo[] newRegions = getHRegionInfos(hTableDescriptor, splitKeys);
checkInitialized();
@ -2044,13 +2044,39 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
}
}
@Override
public NamespaceDescriptor getNamespaceDescriptor(String name) throws IOException {
/**
* Ensure that the specified namespace exists, otherwise throws a NamespaceNotFoundException
*
* @param name the namespace to check
* @throws IOException if the namespace manager is not ready yet.
* @throws NamespaceNotFoundException if the namespace does not exists
*/
private void ensureNamespaceExists(final String name)
throws IOException, NamespaceNotFoundException {
checkNamespaceManagerReady();
NamespaceDescriptor nsd = tableNamespaceManager.get(name);
if (nsd == null) {
throw new NamespaceNotFoundException(name);
}
}
@Override
public NamespaceDescriptor getNamespaceDescriptor(String name) throws IOException {
checkNamespaceManagerReady();
if (cpHost != null) {
cpHost.preGetNamespaceDescriptor(name);
}
NamespaceDescriptor nsd = tableNamespaceManager.get(name);
if (nsd == null) {
throw new NamespaceNotFoundException(name);
}
if (cpHost != null) {
cpHost.postGetNamespaceDescriptor(nsd);
}
return nsd;
}
@ -2076,13 +2102,13 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
@Override
public List<HTableDescriptor> listTableDescriptorsByNamespace(String name) throws IOException {
getNamespaceDescriptor(name); // check that namespace exists
ensureNamespaceExists(name);
return listTableDescriptors(name, null, null, true);
}
@Override
public List<TableName> listTableNamesByNamespace(String name) throws IOException {
getNamespaceDescriptor(name); // check that namespace exists
ensureNamespaceExists(name);
return listTableNames(name, null, true);
}

View File

@ -139,6 +139,28 @@ public class MasterCoprocessorHost
});
}
public void preGetNamespaceDescriptor(final String namespaceName)
throws IOException {
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
@Override
public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
oserver.preGetNamespaceDescriptor(ctx, namespaceName);
}
});
}
public void postGetNamespaceDescriptor(final NamespaceDescriptor ns)
throws IOException {
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
@Override
public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
oserver.postGetNamespaceDescriptor(ctx, ns);
}
});
}
public boolean preListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
throws IOException {
return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {

View File

@ -1184,6 +1184,12 @@ public class AccessController extends BaseMasterAndRegionObserver
requireGlobalPermission("modifyNamespace", Action.ADMIN, ns.getName());
}
@Override
public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx, String namespace)
throws IOException {
requireGlobalPermission("getNamespaceDescriptor", Action.ADMIN, namespace);
}
@Override
public void postListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
List<NamespaceDescriptor> descriptors) throws IOException {

View File

@ -91,6 +91,8 @@ public class TestMasterObserver {
private boolean postDeleteNamespaceCalled;
private boolean preModifyNamespaceCalled;
private boolean postModifyNamespaceCalled;
private boolean preGetNamespaceDescriptorCalled;
private boolean postGetNamespaceDescriptorCalled;
private boolean preListNamespaceDescriptorsCalled;
private boolean postListNamespaceDescriptorsCalled;
private boolean preAddColumnCalled;
@ -171,6 +173,8 @@ public class TestMasterObserver {
postDeleteNamespaceCalled = false;
preModifyNamespaceCalled = false;
postModifyNamespaceCalled = false;
preGetNamespaceDescriptorCalled = false;
postGetNamespaceDescriptorCalled = false;
preListNamespaceDescriptorsCalled = false;
postListNamespaceDescriptorsCalled = false;
preAddColumnCalled = false;
@ -392,6 +396,23 @@ public class TestMasterObserver {
return preModifyNamespaceCalled && !postModifyNamespaceCalled;
}
@Override
public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
String namespace) throws IOException {
preGetNamespaceDescriptorCalled = true;
}
@Override
public void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
NamespaceDescriptor ns) throws IOException {
postGetNamespaceDescriptorCalled = true;
}
public boolean wasGetNamespaceDescriptorCalled() {
return preGetNamespaceDescriptorCalled && postGetNamespaceDescriptorCalled;
}
@Override
public void preListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> env,
List<NamespaceDescriptor> descriptors) throws IOException {
@ -1357,6 +1378,8 @@ public class TestMasterObserver {
assertTrue("Test namespace should be created", cp.wasCreateNamespaceCalled());
assertNotNull(admin.getNamespaceDescriptor(testNamespace));
assertTrue("Test namespace descriptor should have been called",
cp.wasGetNamespaceDescriptorCalled());
// turn off bypass, run the tests again
cp.enableBypass(true);
@ -1367,11 +1390,15 @@ public class TestMasterObserver {
cp.preModifyNamespaceCalledOnly());
assertNotNull(admin.getNamespaceDescriptor(testNamespace));
assertTrue("Test namespace descriptor should have been called",
cp.wasGetNamespaceDescriptorCalled());
admin.deleteNamespace(testNamespace);
assertTrue("Test namespace should not have been deleted", cp.preDeleteNamespaceCalledOnly());
assertNotNull(admin.getNamespaceDescriptor(testNamespace));
assertTrue("Test namespace descriptor should have been called",
cp.wasGetNamespaceDescriptorCalled());
cp.enableBypass(false);
cp.resetStates();

View File

@ -190,6 +190,21 @@ public class TestNamespaceCommands extends SecureTestUtil {
verifyDenied(deleteNamespace, USER_NSP_WRITE, USER_CREATE, USER_RW);
}
@Test
public void testGetNamespaceDescriptor() throws Exception {
AccessTestAction getNamespaceAction = new AccessTestAction() {
public Object run() throws Exception {
ACCESS_CONTROLLER.preGetNamespaceDescriptor(ObserverContext.createAndPrepare(CP_ENV, null),
TEST_NAMESPACE);
return null;
}
};
// verify that superuser or hbase admin can get the namespace descriptor.
verifyAllowed(getNamespaceAction, SUPERUSER, USER_NSP_ADMIN);
// all others should be denied
verifyDenied(getNamespaceAction, USER_NSP_WRITE, USER_CREATE, USER_RW);
}
@Test
public void testListNamespaces() throws Exception {
AccessTestAction listAction = new AccessTestAction() {