HDFS-12907. Allow read-only access to reserved raw for non-superusers. Contributed by Rushabh S Shah.

This commit is contained in:
Kihwal Lee 2017-12-14 14:58:47 -06:00
parent 37efa67e37
commit f5a72424c0
4 changed files with 86 additions and 35 deletions

View File

@ -656,7 +656,14 @@ public class FSDirectory implements Closeable {
byte[][] components = INode.getPathComponents(src); byte[][] components = INode.getPathComponents(src);
boolean isRaw = isReservedRawName(components); boolean isRaw = isReservedRawName(components);
if (isPermissionEnabled && pc != null && isRaw) { if (isPermissionEnabled && pc != null && isRaw) {
switch(dirOp) {
case READ_LINK:
case READ:
break;
default:
pc.checkSuperuserPrivilege(); pc.checkSuperuserPrivilege();
break;
}
} }
components = resolveComponents(components, this); components = resolveComponents(components, this);
INodesInPath iip = INodesInPath.resolve(rootDir, components, isRaw); INodesInPath iip = INodesInPath.resolve(rootDir, components, isRaw);

View File

@ -54,7 +54,8 @@ import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.SECURITY_
* attributes that sometimes need to be exposed. Like SYSTEM namespace * attributes that sometimes need to be exposed. Like SYSTEM namespace
* attributes they are not visible to the user except when getXAttr/getXAttrs * attributes they are not visible to the user except when getXAttr/getXAttrs
* is called on a file or directory in the /.reserved/raw HDFS directory * is called on a file or directory in the /.reserved/raw HDFS directory
* hierarchy. These attributes can only be accessed by the superuser. * hierarchy. These attributes can only be accessed by the user who have
* read access.
* </br> * </br>
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
@ -68,8 +69,7 @@ public class XAttrPermissionFilter {
(xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED && isSuperUser)) { (xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED && isSuperUser)) {
return; return;
} }
if (xAttr.getNameSpace() == XAttr.NameSpace.RAW && if (xAttr.getNameSpace() == XAttr.NameSpace.RAW && isRawPath) {
isRawPath && isSuperUser) {
return; return;
} }
if (XAttrHelper.getPrefixedName(xAttr). if (XAttrHelper.getPrefixedName(xAttr).
@ -112,15 +112,13 @@ public class XAttrPermissionFilter {
} else if (xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED && } else if (xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED &&
isSuperUser) { isSuperUser) {
filteredXAttrs.add(xAttr); filteredXAttrs.add(xAttr);
} else if (xAttr.getNameSpace() == XAttr.NameSpace.RAW && } else if (xAttr.getNameSpace() == XAttr.NameSpace.RAW && isRawPath) {
isSuperUser && isRawPath) {
filteredXAttrs.add(xAttr); filteredXAttrs.add(xAttr);
} else if (XAttrHelper.getPrefixedName(xAttr). } else if (XAttrHelper.getPrefixedName(xAttr).
equals(SECURITY_XATTR_UNREADABLE_BY_SUPERUSER)) { equals(SECURITY_XATTR_UNREADABLE_BY_SUPERUSER)) {
filteredXAttrs.add(xAttr); filteredXAttrs.add(xAttr);
} }
} }
return filteredXAttrs; return filteredXAttrs;
} }
} }

View File

@ -247,7 +247,7 @@ public class TestReservedRawPaths {
} }
@Test(timeout = 120000) @Test(timeout = 120000)
public void testAdminAccessOnly() throws Exception { public void testUserReadAccessOnly() throws Exception {
final Path zone = new Path("zone"); final Path zone = new Path("zone");
final Path slashZone = new Path("/", zone); final Path slashZone = new Path("/", zone);
fs.mkdirs(slashZone); fs.mkdirs(slashZone);
@ -275,34 +275,26 @@ public class TestReservedRawPaths {
} }
}); });
/* Test failure of getFileStatus in reserved/raw as non admin */ /* Test success of getFileStatus in reserved/raw as non admin since
* read is allowed. */
final Path ezRawEncFile = new Path(new Path(reservedRaw, zone), base); final Path ezRawEncFile = new Path(new Path(reservedRaw, zone), base);
DFSTestUtil.createFile(fs, ezRawEncFile, len, (short) 1, 0xFEED); DFSTestUtil.createFile(fs, ezRawEncFile, len, (short) 1, 0xFEED);
user.doAs(new PrivilegedExceptionAction<Object>() { user.doAs(new PrivilegedExceptionAction<Object>() {
@Override @Override
public Object run() throws Exception { public Object run() throws Exception {
final DistributedFileSystem fs = cluster.getFileSystem(); final DistributedFileSystem fs = cluster.getFileSystem();
try {
fs.getFileStatus(ezRawEncFile); fs.getFileStatus(ezRawEncFile);
fail("access to /.reserved/raw is superuser-only operation");
} catch (AccessControlException e) {
assertExceptionContains("Superuser privilege is required", e);
}
return null; return null;
} }
}); });
/* Test failure of listStatus in reserved/raw as non admin */ /* Test success of listStatus in reserved/raw as non admin since read is
* allowed. */
user.doAs(new PrivilegedExceptionAction<Object>() { user.doAs(new PrivilegedExceptionAction<Object>() {
@Override @Override
public Object run() throws Exception { public Object run() throws Exception {
final DistributedFileSystem fs = cluster.getFileSystem(); final DistributedFileSystem fs = cluster.getFileSystem();
try {
fs.listStatus(ezRawEncFile); fs.listStatus(ezRawEncFile);
fail("access to /.reserved/raw is superuser-only operation");
} catch (AccessControlException e) {
assertExceptionContains("Superuser privilege is required", e);
}
return null; return null;
} }
}); });

View File

@ -20,6 +20,7 @@ package org.apache.hadoop.hdfs.server.namenode;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -32,6 +33,7 @@ import org.apache.hadoop.fs.XAttrSetFlag;
import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.DFSTestUtil; import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.IOUtils;
@ -1082,7 +1084,8 @@ public class FSXAttrBaseTest {
{ {
/* /*
* Test that non-root can not do getXAttr in the "raw.*" namespace * Test that user who don'r have read access
* can not do getXAttr in the "raw.*" namespace
*/ */
fs.setXAttr(rawPath, raw1, value1); fs.setXAttr(rawPath, raw1, value1);
user.doAs(new PrivilegedExceptionAction<Object>() { user.doAs(new PrivilegedExceptionAction<Object>() {
@ -1090,7 +1093,7 @@ public class FSXAttrBaseTest {
public Object run() throws Exception { public Object run() throws Exception {
final FileSystem userFs = dfsCluster.getFileSystem(); final FileSystem userFs = dfsCluster.getFileSystem();
try { try {
// non-raw path // raw path
userFs.getXAttr(rawPath, raw1); userFs.getXAttr(rawPath, raw1);
fail("getXAttr should have thrown"); fail("getXAttr should have thrown");
} catch (AccessControlException e) { } catch (AccessControlException e) {
@ -1098,7 +1101,7 @@ public class FSXAttrBaseTest {
} }
try { try {
// raw path // non-raw path
userFs.getXAttr(path, raw1); userFs.getXAttr(path, raw1);
fail("getXAttr should have thrown"); fail("getXAttr should have thrown");
} catch (AccessControlException e) { } catch (AccessControlException e) {
@ -1106,25 +1109,76 @@ public class FSXAttrBaseTest {
} }
/* /*
* Test that only root can see raw.* xattrs returned from listXAttr * Test that only user who have parent directory execute access
* and non-root can't do listXAttrs on /.reserved/raw. * can see raw.* xattrs returned from listXAttr
*/ */
// non-raw path // non-raw path
final List<String> xattrNames = userFs.listXAttrs(path); final List<String> xattrNames = userFs.listXAttrs(path);
assertTrue(xattrNames.size() == 0); assertTrue(xattrNames.size() == 0);
try {
// raw path
userFs.listXAttrs(rawPath);
fail("listXAttrs on raw path should have thrown");
} catch (AccessControlException e) {
// ignore
}
// raw path
List<String> rawXattrs = userFs.listXAttrs(rawPath);
assertTrue(rawXattrs.size() == 1);
assertTrue(rawXattrs.get(0).equals(raw1));
return null; return null;
} }
}); });
fs.removeXAttr(rawPath, raw1); fs.removeXAttr(rawPath, raw1);
} }
{
/*
* Tests that user who have read access are able to do getattr.
*/
Path parentPath = new Path("/foo");
fs.mkdirs(parentPath);
fs.setOwner(parentPath, "user", "mygroup");
// Set only execute permission for others on parent directory so that
// any user can traverse down the directory.
fs.setPermission(parentPath, new FsPermission("701"));
Path childPath = new Path("/foo/bar");
user.doAs(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
final DistributedFileSystem dfs = dfsCluster.getFileSystem();
DFSTestUtil.createFile(dfs, childPath, 1024, (short) 1, 0xFEED);
dfs.setPermission(childPath, new FsPermission("740"));
return null;
}
});
Path rawChildPath =
new Path("/.reserved/raw" + childPath.toString());
fs.setXAttr(new Path("/.reserved/raw/foo/bar"), raw1, value1);
user.doAs(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
final DistributedFileSystem dfs = dfsCluster.getFileSystem();
// Make sure user have access to raw xattr.
byte[] xattr = dfs.getXAttr(rawChildPath, raw1);
assertEquals(Arrays.toString(value1), Arrays.toString(xattr));
return null;
}
});
final UserGroupInformation fakeUser = UserGroupInformation
.createUserForTesting("fakeUser", new String[] {"fakeGroup"});
fakeUser.doAs(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
final DistributedFileSystem dfs = dfsCluster.getFileSystem();
try {
// Make sure user who don't have read access to file can't access
// raw xattr.
dfs.getXAttr(path, raw1);
fail("should have thrown AccessControlException");
} catch (AccessControlException ace) {
// expected
}
return null;
}
});
// fs.removeXAttr(rawPath, raw1);
}
} }
/** /**