HDFS-15051. RBF: Impose directory level permissions for Mount entries. Contributed by Xiaoqiao He.
This commit is contained in:
parent
d3b5951572
commit
4a3eb10972
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.hdfs.server.federation.router.RouterAdminServer;
|
import org.apache.hadoop.hdfs.server.federation.router.RouterAdminServer;
|
||||||
import org.apache.hadoop.hdfs.server.federation.router.RouterPermissionChecker;
|
import org.apache.hadoop.hdfs.server.federation.router.RouterPermissionChecker;
|
||||||
@ -61,24 +62,69 @@ public MountTableStoreImpl(StateStoreDriver driver) {
|
|||||||
super(driver);
|
super(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a mount table entry can be accessed by the current context.
|
||||||
|
*
|
||||||
|
* @param src mount entry being accessed
|
||||||
|
* @param action type of action being performed on the mount entry
|
||||||
|
* @throws AccessControlException if mount table cannot be accessed
|
||||||
|
*/
|
||||||
|
private void checkMountTableEntryPermission(String src, FsAction action)
|
||||||
|
throws IOException {
|
||||||
|
final MountTable partial = MountTable.newInstance();
|
||||||
|
partial.setSourcePath(src);
|
||||||
|
final Query<MountTable> query = new Query<>(partial);
|
||||||
|
final MountTable entry = getDriver().get(getRecordClass(), query);
|
||||||
|
if (entry != null) {
|
||||||
|
RouterPermissionChecker pc = RouterAdminServer.getPermissionChecker();
|
||||||
|
if (pc != null) {
|
||||||
|
pc.checkPermission(entry, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check parent path permission recursively. It needs WRITE permission
|
||||||
|
* of the nearest parent entry and other EXECUTE permission.
|
||||||
|
* @param src mount entry being checked
|
||||||
|
* @throws AccessControlException if mount table cannot be accessed
|
||||||
|
*/
|
||||||
|
private void checkMountTablePermission(final String src) throws IOException {
|
||||||
|
String parent = src.substring(0, src.lastIndexOf(Path.SEPARATOR));
|
||||||
|
checkMountTableEntryPermission(parent, FsAction.WRITE);
|
||||||
|
while (!parent.isEmpty()) {
|
||||||
|
parent = parent.substring(0, parent.lastIndexOf(Path.SEPARATOR));
|
||||||
|
checkMountTableEntryPermission(parent, FsAction.EXECUTE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When add mount table entry, it needs WRITE permission of the nearest parent
|
||||||
|
* entry if exist, and EXECUTE permission of other ancestor entries.
|
||||||
|
* @param request add mount table entry request
|
||||||
|
* @return add mount table entry response
|
||||||
|
* @throws IOException if mount table cannot be accessed
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AddMountTableEntryResponse addMountTableEntry(
|
public AddMountTableEntryResponse addMountTableEntry(
|
||||||
AddMountTableEntryRequest request) throws IOException {
|
AddMountTableEntryRequest request) throws IOException {
|
||||||
MountTable mountTable = request.getEntry();
|
MountTable mountTable = request.getEntry();
|
||||||
if (mountTable != null) {
|
if (mountTable != null) {
|
||||||
RouterPermissionChecker pc = RouterAdminServer.getPermissionChecker();
|
|
||||||
if (pc != null) {
|
|
||||||
pc.checkPermission(mountTable, FsAction.WRITE);
|
|
||||||
}
|
|
||||||
mountTable.validate();
|
mountTable.validate();
|
||||||
}
|
final String src = mountTable.getSourcePath();
|
||||||
|
checkMountTablePermission(src);
|
||||||
boolean status = getDriver().put(mountTable, false, true);
|
boolean status = getDriver().put(mountTable, false, true);
|
||||||
AddMountTableEntryResponse response =
|
AddMountTableEntryResponse response =
|
||||||
AddMountTableEntryResponse.newInstance();
|
AddMountTableEntryResponse.newInstance();
|
||||||
response.setStatus(status);
|
response.setStatus(status);
|
||||||
updateCacheAllRouters();
|
updateCacheAllRouters();
|
||||||
return response;
|
return response;
|
||||||
|
} else {
|
||||||
|
AddMountTableEntryResponse response =
|
||||||
|
AddMountTableEntryResponse.newInstance();
|
||||||
|
response.setStatus(false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,19 +132,21 @@ public UpdateMountTableEntryResponse updateMountTableEntry(
|
|||||||
UpdateMountTableEntryRequest request) throws IOException {
|
UpdateMountTableEntryRequest request) throws IOException {
|
||||||
MountTable mountTable = request.getEntry();
|
MountTable mountTable = request.getEntry();
|
||||||
if (mountTable != null) {
|
if (mountTable != null) {
|
||||||
RouterPermissionChecker pc = RouterAdminServer.getPermissionChecker();
|
|
||||||
if (pc != null) {
|
|
||||||
pc.checkPermission(mountTable, FsAction.WRITE);
|
|
||||||
}
|
|
||||||
mountTable.validate();
|
mountTable.validate();
|
||||||
}
|
final String srcPath = mountTable.getSourcePath();
|
||||||
|
checkMountTableEntryPermission(srcPath, FsAction.WRITE);
|
||||||
boolean status = getDriver().put(mountTable, true, true);
|
boolean status = getDriver().put(mountTable, true, true);
|
||||||
UpdateMountTableEntryResponse response =
|
UpdateMountTableEntryResponse response =
|
||||||
UpdateMountTableEntryResponse.newInstance();
|
UpdateMountTableEntryResponse.newInstance();
|
||||||
response.setStatus(status);
|
response.setStatus(status);
|
||||||
updateCacheAllRouters();
|
updateCacheAllRouters();
|
||||||
return response;
|
return response;
|
||||||
|
} else {
|
||||||
|
UpdateMountTableEntryResponse response =
|
||||||
|
UpdateMountTableEntryResponse.newInstance();
|
||||||
|
response.setStatus(false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -519,6 +519,187 @@ public void testMountTableDefaultACL() throws Exception {
|
|||||||
assertEquals((short) 0755, mountTable.getMode().toShort());
|
assertEquals((short) 0755, mountTable.getMode().toShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateMountTableWithoutPermission() throws Exception {
|
||||||
|
UserGroupInformation superUser = UserGroupInformation.getCurrentUser();
|
||||||
|
String superUserName = superUser.getShortUserName();
|
||||||
|
// re-set system out for testing
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
|
||||||
|
try {
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// add mount table using super user.
|
||||||
|
String[] argv = new String[]{"-add", "/testpath3-1", "ns0", "/testdir3-1",
|
||||||
|
"-owner", superUserName, "-group", superUserName, "-mode", "755"};
|
||||||
|
assertEquals(0, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
UserGroupInformation remoteUser = UserGroupInformation
|
||||||
|
.createRemoteUser(TEST_USER);
|
||||||
|
UserGroupInformation.setLoginUser(remoteUser);
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// update mount table using normal user
|
||||||
|
argv = new String[]{"-update", "/testpath3-1", "ns0", "/testdir3-2",
|
||||||
|
"-owner", TEST_USER, "-group", TEST_USER, "-mode", "777"};
|
||||||
|
assertEquals("Normal user update mount table which created by " +
|
||||||
|
"superuser unexpected.", -1, ToolRunner.run(admin, argv));
|
||||||
|
} finally {
|
||||||
|
// set back login user
|
||||||
|
UserGroupInformation.setLoginUser(superUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperateMountTableWithGroupPermission() throws Exception {
|
||||||
|
UserGroupInformation superUser = UserGroupInformation.getCurrentUser();
|
||||||
|
// re-set system out for testing
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
|
||||||
|
try {
|
||||||
|
String testUserA = "test-user-a";
|
||||||
|
String testUserB = "test-user-b";
|
||||||
|
String testUserC = "test-user-c";
|
||||||
|
String testUserD = "test-user-d";
|
||||||
|
String testGroup = "test-group";
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// add mount point with usera.
|
||||||
|
UserGroupInformation userA = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserA, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userA);
|
||||||
|
|
||||||
|
String[] argv = new String[]{"-add", "/testpath4-1", "ns0", "/testdir4-1",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "775"};
|
||||||
|
assertEquals("Normal user can't add mount table unexpected.", 0,
|
||||||
|
ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// update mount point with userb which is same group with owner.
|
||||||
|
UserGroupInformation userB = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserB, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userB);
|
||||||
|
argv = new String[]{"-update", "/testpath4-1", "ns0", "/testdir4-2",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "775"};
|
||||||
|
assertEquals("Another user in same group can't update mount table " +
|
||||||
|
"unexpected.", 0, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// update mount point with userc which is not same group with owner.
|
||||||
|
UserGroupInformation userC = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserC, new String[] {});
|
||||||
|
UserGroupInformation.setLoginUser(userC);
|
||||||
|
argv = new String[]{"-update", "/testpath4-1", "ns0", "/testdir4-3",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "775"};
|
||||||
|
assertEquals("Another user not in same group have no permission but " +
|
||||||
|
"update mount table successful unexpected.", -1,
|
||||||
|
ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// add mount point with userd but immediate parent of mount point
|
||||||
|
// does not exist.
|
||||||
|
UserGroupInformation userD = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserD, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userD);
|
||||||
|
argv = new String[]{"-add", "/testpath4-1/foo/bar", "ns0",
|
||||||
|
"/testdir4-1/foo/bar", "-owner", testUserD, "-group", testGroup,
|
||||||
|
"-mode", "775"};
|
||||||
|
assertEquals("Normal user can't add mount table unexpected.", 0,
|
||||||
|
ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// test remove mount point with userc.
|
||||||
|
UserGroupInformation.setLoginUser(userC);
|
||||||
|
argv = new String[]{"-rm", "/testpath4-1"};
|
||||||
|
assertEquals(-1, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// test remove mount point with userb.
|
||||||
|
UserGroupInformation.setLoginUser(userB);
|
||||||
|
assertEquals("Another user in same group can't remove mount table " +
|
||||||
|
"unexpected.", 0, ToolRunner.run(admin, argv));
|
||||||
|
} finally {
|
||||||
|
// set back login user
|
||||||
|
UserGroupInformation.setLoginUser(superUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperateMountTableWithSuperUserPermission() throws Exception {
|
||||||
|
UserGroupInformation superUser = UserGroupInformation.getCurrentUser();
|
||||||
|
// re-set system out for testing
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
|
||||||
|
try {
|
||||||
|
String testUserA = "test-user-a";
|
||||||
|
String testGroup = "test-group";
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// add mount point with usera.
|
||||||
|
UserGroupInformation userA = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserA, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userA);
|
||||||
|
String[] argv = new String[]{"-add", "/testpath5-1", "ns0", "/testdir5-1",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "755"};
|
||||||
|
assertEquals(0, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// test update mount point with super user.
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
UserGroupInformation.setLoginUser(superUser);
|
||||||
|
argv = new String[]{"-update", "/testpath5-1", "ns0", "/testdir5-2",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "755"};
|
||||||
|
assertEquals("Super user can't update mount table unexpected.", 0,
|
||||||
|
ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// test remove mount point with super user.
|
||||||
|
argv = new String[]{"-rm", "/testpath5-1"};
|
||||||
|
assertEquals("Super user can't remove mount table unexpected.", 0,
|
||||||
|
ToolRunner.run(admin, argv));
|
||||||
|
} finally {
|
||||||
|
// set back login user
|
||||||
|
UserGroupInformation.setLoginUser(superUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddMountTableIfParentExist() throws Exception {
|
||||||
|
UserGroupInformation superUser = UserGroupInformation.getCurrentUser();
|
||||||
|
// re-set system out for testing
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
|
||||||
|
try {
|
||||||
|
String testUserA = "test-user-a";
|
||||||
|
String testUserB = "test-user-b";
|
||||||
|
String testGroup = "test-group";
|
||||||
|
|
||||||
|
stateStore.loadCache(MountTableStoreImpl.class, true);
|
||||||
|
// add mount point with usera.
|
||||||
|
UserGroupInformation userA = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserA, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userA);
|
||||||
|
String[] argv = new String[]{"-add", "/testpath6-1", "ns0", "/testdir6-1",
|
||||||
|
"-owner", testUserA, "-group", testGroup, "-mode", "755"};
|
||||||
|
assertEquals(0, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// add mount point with userb will be success since the nearest parent
|
||||||
|
// does not exist but have other EXECUTE permission.
|
||||||
|
UserGroupInformation userB = UserGroupInformation.createUserForTesting(
|
||||||
|
testUserB, new String[] {testGroup});
|
||||||
|
UserGroupInformation.setLoginUser(userB);
|
||||||
|
argv = new String[]{"-add", "/testpath6-1/parent/foo", "ns0",
|
||||||
|
"/testdir6-1/parent/foo", "-owner", testUserA, "-group", testGroup,
|
||||||
|
"-mode", "755"};
|
||||||
|
assertEquals(0, ToolRunner.run(admin, argv));
|
||||||
|
|
||||||
|
// add mount point with userb will be failure since the nearest parent
|
||||||
|
// does exist but no WRITE permission.
|
||||||
|
argv = new String[]{"-add", "/testpath6-1/foo", "ns0",
|
||||||
|
"/testdir6-1/foo", "-owner", testUserA, "-group", testGroup,
|
||||||
|
"-mode", "755"};
|
||||||
|
assertEquals(-1, ToolRunner.run(admin, argv));
|
||||||
|
} finally {
|
||||||
|
// set back login user
|
||||||
|
UserGroupInformation.setLoginUser(superUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMountTablePermissions() throws Exception {
|
public void testMountTablePermissions() throws Exception {
|
||||||
// re-set system out for testing
|
// re-set system out for testing
|
||||||
|
Loading…
Reference in New Issue
Block a user