HDFS-16259. Catch and re-throw sub-classes of AccessControlException thrown by any permission provider plugins (eg Ranger) (#3598)

This commit is contained in:
Stephen O'Donnell 2021-11-02 11:14:48 +00:00 committed by GitHub
parent 618fea27d2
commit 2f35cc36cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 25 deletions

View File

@ -273,6 +273,7 @@ void checkPermission(INodesInPath inodesInPath, boolean doCheckOwner,
AccessControlEnforcer enforcer = getAccessControlEnforcer(); AccessControlEnforcer enforcer = getAccessControlEnforcer();
String opType = operationType.get(); String opType = operationType.get();
try {
if (this.authorizeWithContext && opType != null) { if (this.authorizeWithContext && opType != null) {
INodeAttributeProvider.AuthorizationContext.Builder builder = INodeAttributeProvider.AuthorizationContext.Builder builder =
new INodeAttributeProvider.AuthorizationContext.Builder(); new INodeAttributeProvider.AuthorizationContext.Builder();
@ -299,6 +300,15 @@ void checkPermission(INodesInPath inodesInPath, boolean doCheckOwner,
inodes, components, snapshotId, path, ancestorIndex, doCheckOwner, inodes, components, snapshotId, path, ancestorIndex, doCheckOwner,
ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir); ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir);
} }
} catch (AccessControlException ace) {
Class<?> exceptionClass = ace.getClass();
if (exceptionClass.equals(AccessControlException.class)
|| exceptionClass.equals(TraverseAccessControlException.class)) {
throw ace;
}
// Only form a new ACE for subclasses which come from external enforcers
throw new AccessControlException(ace);
}
} }

View File

@ -48,6 +48,8 @@
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.junit.Assert.fail;
public class TestINodeAttributeProvider { public class TestINodeAttributeProvider {
private static final Logger LOG = private static final Logger LOG =
LoggerFactory.getLogger(TestINodeAttributeProvider.class); LoggerFactory.getLogger(TestINodeAttributeProvider.class);
@ -57,6 +59,15 @@ public class TestINodeAttributeProvider {
private static final short HDFS_PERMISSION = 0777; private static final short HDFS_PERMISSION = 0777;
private static final short PROVIDER_PERMISSION = 0770; private static final short PROVIDER_PERMISSION = 0770;
private static boolean runPermissionCheck = false; private static boolean runPermissionCheck = false;
private static boolean shouldThrowAccessException = false;
public static class MyAuthorizationProviderAccessException
extends AccessControlException {
public MyAuthorizationProviderAccessException() {
super();
}
};
public static class MyAuthorizationProvider extends INodeAttributeProvider { public static class MyAuthorizationProvider extends INodeAttributeProvider {
@ -82,6 +93,9 @@ public void checkPermission(String fsOwner, String supergroup,
ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir); ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir);
} }
CALLED.add("checkPermission|" + ancestorAccess + "|" + parentAccess + "|" + access); CALLED.add("checkPermission|" + ancestorAccess + "|" + parentAccess + "|" + access);
if (shouldThrowAccessException) {
throw new MyAuthorizationProviderAccessException();
}
} }
@Override @Override
@ -96,6 +110,9 @@ public void checkPermissionWithContext(
CALLED.add("checkPermission|" + authzContext.getAncestorAccess() CALLED.add("checkPermission|" + authzContext.getAncestorAccess()
+ "|" + authzContext.getParentAccess() + "|" + authzContext + "|" + authzContext.getParentAccess() + "|" + authzContext
.getAccess()); .getAccess());
if (shouldThrowAccessException) {
throw new MyAuthorizationProviderAccessException();
}
} }
} }
@ -238,6 +255,7 @@ public void cleanUp() throws IOException {
miniDFS = null; miniDFS = null;
} }
runPermissionCheck = false; runPermissionCheck = false;
shouldThrowAccessException = false;
Assert.assertTrue(CALLED.contains("stop")); Assert.assertTrue(CALLED.contains("stop"));
} }
@ -457,6 +475,44 @@ public Void run() throws Exception {
}); });
} }
@Test
// HDFS-16529 - Ensure enforcer AccessControlException subclass are caught
// and re-thrown as plain ACE exceptions.
public void testSubClassedAccessControlExceptions() throws Exception {
FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0));
shouldThrowAccessException = true;
final Path userPath = new Path("/user");
final Path authz = new Path("/user/authz");
final Path authzChild = new Path("/user/authz/child2");
fs.mkdirs(userPath);
fs.setPermission(userPath, new FsPermission(HDFS_PERMISSION));
fs.mkdirs(authz);
fs.setPermission(authz, new FsPermission(HDFS_PERMISSION));
fs.mkdirs(authzChild);
fs.setPermission(authzChild, new FsPermission(HDFS_PERMISSION));
UserGroupInformation ugi = UserGroupInformation.createUserForTesting("u1",
new String[]{"g1"});
ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0));
try {
fs.access(authzChild, FsAction.ALL);
fail("Exception should be thrown");
// The DFS Client will get a RemoteException containing an
// AccessControlException (ACE). If the ACE is a subclass of ACE then
// the client does not unwrap it correctly. The change in HDFS-16529
// is to ensure ACE is always thrown rather than a sub class to avoid
// this issue.
} catch (AccessControlException ace) {
Assert.assertEquals(AccessControlException.class, ace.getClass());
}
return null;
}
});
}
@Test @Test
// HDFS-15165 - ContentSummary calls should use the provider permissions(if // HDFS-15165 - ContentSummary calls should use the provider permissions(if