HDFS-12907. Allow read-only access to reserved raw for non-superusers. Contributed by Rushabh S Shah.
This commit is contained in:
parent
37efa67e37
commit
f5a72424c0
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue