HDFS-16901: RBF: Propagates real user's username via the caller context, when a proxy user is being used. (#5346)

This commit is contained in:
Simbarashe Dzinamarira 2023-02-22 13:58:44 -08:00 committed by Owen O'Malley
parent 9a89deca1d
commit 5fe19a0f01
3 changed files with 50 additions and 3 deletions

View File

@ -47,6 +47,7 @@ public final class CallerContext {
// field names
public static final String CLIENT_IP_STR = "clientIp";
public static final String CLIENT_PORT_STR = "clientPort";
public static final String REAL_USER_STR = "realUser";
/** The caller context.
*

View File

@ -423,7 +423,7 @@ private Object invokeMethod(
+ router.getRouterId());
}
addClientIpToCallerContext();
addClientInfoToCallerContext(ugi);
Object ret = null;
if (rpcMonitor != null) {
@ -541,19 +541,24 @@ private Object invokeMethod(
/**
* For tracking which is the actual client address.
* It adds trace info "clientIp:ip" and "clientPort:port"
* It adds trace info "clientIp:ip", "clientPort:port" and "realUser:userName"
* in the caller context, removing the old values if they were
* already present.
*/
private void addClientIpToCallerContext() {
private void addClientInfoToCallerContext(UserGroupInformation ugi) {
CallerContext ctx = CallerContext.getCurrent();
String origContext = ctx == null ? null : ctx.getContext();
byte[] origSignature = ctx == null ? null : ctx.getSignature();
String realUser = null;
if (ugi.getRealUser() != null) {
realUser = ugi.getRealUser().getUserName();
}
CallerContext.Builder builder =
new CallerContext.Builder("", contextFieldSeparator)
.append(CallerContext.CLIENT_IP_STR, Server.getRemoteAddress())
.append(CallerContext.CLIENT_PORT_STR,
Integer.toString(Server.getRemotePort()))
.append(CallerContext.REAL_USER_STR, realUser)
.setSignature(origSignature);
// Append the original caller context
if (origContext != null) {

View File

@ -39,6 +39,7 @@
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -210,6 +211,14 @@ public static void globalSetUp() throws Exception {
cluster.setIndependentDNs();
Configuration conf = new Configuration();
// Setup proxy users.
conf.set("hadoop.proxyuser.testRealUser.groups", "*");
conf.set("hadoop.proxyuser.testRealUser.hosts", "*");
String loginUser = UserGroupInformation.getLoginUser().getUserName();
conf.set(String.format("hadoop.proxyuser.%s.groups", loginUser), "*");
conf.set(String.format("hadoop.proxyuser.%s.hosts", loginUser), "*");
// Enable IP proxy users.
conf.set(DFSConfigKeys.DFS_NAMENODE_IP_PROXY_USERS, "placeholder");
conf.setInt(DFSConfigKeys.DFS_LIST_LIMIT, 5);
cluster.addNamenodeOverrides(conf);
// Start NNs and DNs and wait until ready
@ -1871,6 +1880,38 @@ public void testMkdirsWithCallerContext() throws IOException {
assertTrue(verifyFileExists(routerFS, dirPath));
}
@Test
public void testRealUserPropagationInCallerContext()
throws IOException, InterruptedException {
GenericTestUtils.LogCapturer auditlog =
GenericTestUtils.LogCapturer.captureLogs(FSNamesystem.auditLog);
// Current callerContext is null
assertNull(CallerContext.getCurrent());
UserGroupInformation loginUser = UserGroupInformation.getLoginUser();
UserGroupInformation realUser = UserGroupInformation
.createUserForTesting("testRealUser", new String[]{"group"});
UserGroupInformation proxyUser = UserGroupInformation
.createProxyUser("testProxyUser", realUser);
FileSystem proxyFs = proxyUser.doAs(
(PrivilegedExceptionAction<FileSystem>) () -> router.getFileSystem());
proxyFs.listStatus(new Path("/"));
final String logOutput = auditlog.getOutput();
// Login user, which is used as the router's user, is different from the realUser.
assertNotEquals(loginUser.getUserName(), realUser.getUserName());
// Login user is used in the audit log's ugi field.
assertTrue("The login user is the proxyUser in the UGI field",
logOutput.contains(String.format("ugi=%s (auth:PROXY) via %s (auth:SIMPLE)",
proxyUser.getUserName(),
loginUser.getUserName())));
// Real user is added to the caller context.
assertTrue("The audit log should contain the real user.",
logOutput.contains(String.format("realUser:%s", realUser.getUserName())));
}
@Test
public void testSetBalancerBandwidth() throws Exception {
long defaultBandwidth =