HADOOP-9929. Insufficient permission for a path reported as file not found. (Contributed by Colin Patrick McCabe)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1524611 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Colin McCabe 2013-09-19 02:09:43 +00:00
parent f7eb75fa89
commit 1c4f4a38ca
3 changed files with 87 additions and 19 deletions

View File

@ -366,6 +366,9 @@ Release 2.3.0 - UNRELEASED
HADOOP-9350. Hadoop not building against Java7 on OSX HADOOP-9350. Hadoop not building against Java7 on OSX
(Robert Kanter via stevel) (Robert Kanter via stevel)
HADOOP-9929. Insufficient permissions for a path reported as file not found.
(Contributed by Colin Patrick McCabe)
Release 2.2.0 - UNRELEASED Release 2.2.0 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.fs; package org.apache.hadoop.fs;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -50,26 +51,26 @@ class Globber {
this.filter = filter; this.filter = filter;
} }
private FileStatus getFileStatus(Path path) { private FileStatus getFileStatus(Path path) throws IOException {
try { try {
if (fs != null) { if (fs != null) {
return fs.getFileStatus(path); return fs.getFileStatus(path);
} else { } else {
return fc.getFileStatus(path); return fc.getFileStatus(path);
} }
} catch (IOException e) { } catch (FileNotFoundException e) {
return null; return null;
} }
} }
private FileStatus[] listStatus(Path path) { private FileStatus[] listStatus(Path path) throws IOException {
try { try {
if (fs != null) { if (fs != null) {
return fs.listStatus(path); return fs.listStatus(path);
} else { } else {
return fc.util().listStatus(path); return fc.util().listStatus(path);
} }
} catch (IOException e) { } catch (FileNotFoundException e) {
return new FileStatus[0]; return new FileStatus[0];
} }
} }

View File

@ -20,6 +20,7 @@ package org.apache.hadoop.fs;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@ -27,10 +28,15 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.fs.permission.FsPermission;
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.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.junit.*; import org.junit.*;
public class TestGlobPaths { public class TestGlobPaths {
private static final UserGroupInformation unprivilegedUser =
UserGroupInformation.createRemoteUser("myuser");
static class RegexPathFilter implements PathFilter { static class RegexPathFilter implements PathFilter {
private final String regex; private final String regex;
@ -47,17 +53,33 @@ public class TestGlobPaths {
static private MiniDFSCluster dfsCluster; static private MiniDFSCluster dfsCluster;
static private FileSystem fs; static private FileSystem fs;
static private FileSystem unprivilegedFs;
static private FileContext fc; static private FileContext fc;
static private FileContext unprivilegedFc;
static final private int NUM_OF_PATHS = 4; static final private int NUM_OF_PATHS = 4;
static private String USER_DIR; static private String USER_DIR;
private Path[] path = new Path[NUM_OF_PATHS]; private Path[] path = new Path[NUM_OF_PATHS];
@BeforeClass @BeforeClass
public static void setUp() throws Exception { public static void setUp() throws Exception {
Configuration conf = new HdfsConfiguration(); final Configuration conf = new HdfsConfiguration();
dfsCluster = new MiniDFSCluster.Builder(conf).build(); dfsCluster = new MiniDFSCluster.Builder(conf).build();
fs = FileSystem.get(conf); fs = FileSystem.get(conf);
unprivilegedFs =
unprivilegedUser.doAs(new PrivilegedExceptionAction<FileSystem>() {
@Override
public FileSystem run() throws IOException {
return FileSystem.get(conf);
}
});
fc = FileContext.getFileContext(conf); fc = FileContext.getFileContext(conf);
unprivilegedFc =
unprivilegedUser.doAs(new PrivilegedExceptionAction<FileContext>() {
@Override
public FileContext run() throws IOException {
return FileContext.getFileContext(conf);
}
});
USER_DIR = fs.getHomeDirectory().toUri().getPath().toString(); USER_DIR = fs.getHomeDirectory().toUri().getPath().toString();
} }
@ -781,8 +803,8 @@ public class TestGlobPaths {
* A glob test that can be run on either FileContext or FileSystem. * A glob test that can be run on either FileContext or FileSystem.
*/ */
private static interface FSTestWrapperGlobTest { private static interface FSTestWrapperGlobTest {
void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrapper,
throws Exception; FileSystem fs, FileContext fc) throws Exception;
} }
/** /**
@ -791,7 +813,8 @@ public class TestGlobPaths {
private void testOnFileSystem(FSTestWrapperGlobTest test) throws Exception { private void testOnFileSystem(FSTestWrapperGlobTest test) throws Exception {
try { try {
fc.mkdir(new Path(USER_DIR), FsPermission.getDefault(), true); fc.mkdir(new Path(USER_DIR), FsPermission.getDefault(), true);
test.run(new FileSystemTestWrapper(fs), fs, null); test.run(new FileSystemTestWrapper(fs),
new FileSystemTestWrapper(unprivilegedFs), fs, null);
} finally { } finally {
fc.delete(new Path(USER_DIR), true); fc.delete(new Path(USER_DIR), true);
} }
@ -803,7 +826,8 @@ public class TestGlobPaths {
private void testOnFileContext(FSTestWrapperGlobTest test) throws Exception { private void testOnFileContext(FSTestWrapperGlobTest test) throws Exception {
try { try {
fs.mkdirs(new Path(USER_DIR)); fs.mkdirs(new Path(USER_DIR));
test.run(new FileContextTestWrapper(fc), null, fc); test.run(new FileContextTestWrapper(fc),
new FileContextTestWrapper(unprivilegedFc), null, fc);
} finally { } finally {
cleanupDFS(); cleanupDFS();
} }
@ -834,8 +858,8 @@ public class TestGlobPaths {
* Test globbing through symlinks. * Test globbing through symlinks.
*/ */
private static class TestGlobWithSymlinks implements FSTestWrapperGlobTest { private static class TestGlobWithSymlinks implements FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
throws Exception { FileSystem fs, FileContext fc) throws Exception {
// Test that globbing through a symlink to a directory yields a path // Test that globbing through a symlink to a directory yields a path
// containing that symlink. // containing that symlink.
wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(), wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(),
@ -886,8 +910,8 @@ public class TestGlobPaths {
*/ */
private static class TestGlobWithSymlinksToSymlinks implements private static class TestGlobWithSymlinksToSymlinks implements
FSTestWrapperGlobTest { FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
throws Exception { FileSystem fs, FileContext fc) throws Exception {
// Test that globbing through a symlink to a symlink to a directory // Test that globbing through a symlink to a symlink to a directory
// fully resolves // fully resolves
wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(), wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(),
@ -961,8 +985,8 @@ public class TestGlobPaths {
*/ */
private static class TestGlobSymlinksWithCustomPathFilter implements private static class TestGlobSymlinksWithCustomPathFilter implements
FSTestWrapperGlobTest { FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
throws Exception { FileSystem fs, FileContext fc) throws Exception {
// Test that globbing through a symlink to a symlink to a directory // Test that globbing through a symlink to a symlink to a directory
// fully resolves // fully resolves
wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(), wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(),
@ -1009,8 +1033,8 @@ public class TestGlobPaths {
* Test that globStatus fills in the scheme even when it is not provided. * Test that globStatus fills in the scheme even when it is not provided.
*/ */
private static class TestGlobFillsInScheme implements FSTestWrapperGlobTest { private static class TestGlobFillsInScheme implements FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
throws Exception { FileSystem fs, FileContext fc) throws Exception {
// Verify that the default scheme is hdfs, when we don't supply one. // Verify that the default scheme is hdfs, when we don't supply one.
wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(), wrap.mkdir(new Path(USER_DIR + "/alpha"), FsPermission.getDirDefault(),
false); false);
@ -1052,8 +1076,8 @@ public class TestGlobPaths {
* Test that globStatus works with relative paths. * Test that globStatus works with relative paths.
**/ **/
private static class TestRelativePath implements FSTestWrapperGlobTest { private static class TestRelativePath implements FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FileSystem fs, FileContext fc) public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
throws Exception { FileSystem fs, FileContext fc) throws Exception {
String[] files = new String[] { "a", "abc", "abc.p", "bacd" }; String[] files = new String[] { "a", "abc", "abc.p", "bacd" };
Path[] path = new Path[files.length]; Path[] path = new Path[files.length];
@ -1086,4 +1110,44 @@ public class TestGlobPaths {
public void testRelativePathOnFC() throws Exception { public void testRelativePathOnFC() throws Exception {
testOnFileContext(new TestRelativePath()); testOnFileContext(new TestRelativePath());
} }
/**
* Test that trying to glob through a directory we don't have permission
* to list fails with AccessControlException rather than succeeding or
* throwing any other exception.
**/
private static class TestGlobAccessDenied implements FSTestWrapperGlobTest {
public void run(FSTestWrapper wrap, FSTestWrapper unprivilegedWrap,
FileSystem fs, FileContext fc) throws Exception {
wrap.mkdir(new Path("/nopermission/val"),
new FsPermission((short)0777), true);
wrap.mkdir(new Path("/norestrictions/val"),
new FsPermission((short)0777), true);
wrap.setPermission(new Path("/nopermission"),
new FsPermission((short)0));
try {
unprivilegedWrap.globStatus(new Path("/no*/*"),
new AcceptAllPathFilter());
Assert.fail("expected to get an AccessControlException when " +
"globbing through a directory we don't have permissions " +
"to list.");
} catch (AccessControlException ioe) {
}
Assert.assertEquals("/norestrictions/val",
TestPath.mergeStatuses(unprivilegedWrap.globStatus(
new Path("/norestrictions/*"),
new AcceptAllPathFilter())));
}
}
@Test
public void testGlobAccessDeniedOnFS() throws Exception {
testOnFileSystem(new TestGlobAccessDenied());
}
@Test
public void testGlobAccessDeniedOnFC() throws Exception {
testOnFileContext(new TestGlobAccessDenied());
}
} }