YARN-707. Add user info in the YARN ClientToken. Contributed by Vinod Kumar Vavilapalli
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1517073 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9ee38f3a84
commit
f1638fdf94
|
@ -43,6 +43,8 @@ Release 2.1.1-beta - UNRELEASED
|
|||
|
||||
YARN-589. Expose a REST API for monitoring the fair scheduler (Sandy Ryza).
|
||||
|
||||
YARN-707. Add user info in the YARN ClientToken (vinodkv via jlowe)
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
BUG FIXES
|
||||
|
|
|
@ -39,6 +39,7 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
|
|||
public static final Text KIND_NAME = new Text("YARN_CLIENT_TOKEN");
|
||||
|
||||
private ApplicationAttemptId applicationAttemptId;
|
||||
private Text applicationSubmitter = new Text();
|
||||
|
||||
// TODO: Add more information in the tokenID such that it is not
|
||||
// transferrable, more secure etc.
|
||||
|
@ -46,21 +47,27 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
|
|||
public ClientToAMTokenIdentifier() {
|
||||
}
|
||||
|
||||
public ClientToAMTokenIdentifier(ApplicationAttemptId id) {
|
||||
public ClientToAMTokenIdentifier(ApplicationAttemptId id, String appSubmitter) {
|
||||
this();
|
||||
this.applicationAttemptId = id;
|
||||
this.applicationSubmitter = new Text(appSubmitter);
|
||||
}
|
||||
|
||||
public ApplicationAttemptId getApplicationAttemptID() {
|
||||
return this.applicationAttemptId;
|
||||
}
|
||||
|
||||
public String getApplicationSubmitter() {
|
||||
return this.applicationSubmitter.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput out) throws IOException {
|
||||
out.writeLong(this.applicationAttemptId.getApplicationId()
|
||||
.getClusterTimestamp());
|
||||
out.writeInt(this.applicationAttemptId.getApplicationId().getId());
|
||||
out.writeInt(this.applicationAttemptId.getAttemptId());
|
||||
this.applicationSubmitter.write(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,6 +75,7 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
|
|||
this.applicationAttemptId =
|
||||
ApplicationAttemptId.newInstance(
|
||||
ApplicationId.newInstance(in.readLong(), in.readInt()), in.readInt());
|
||||
this.applicationSubmitter.readFields(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,10 +85,11 @@ public class ClientToAMTokenIdentifier extends TokenIdentifier {
|
|||
|
||||
@Override
|
||||
public UserGroupInformation getUser() {
|
||||
if (this.applicationAttemptId == null) {
|
||||
if (this.applicationSubmitter == null) {
|
||||
return null;
|
||||
}
|
||||
return UserGroupInformation.createRemoteUser(this.applicationAttemptId.toString());
|
||||
return UserGroupInformation.createRemoteUser(this.applicationSubmitter
|
||||
.toString());
|
||||
}
|
||||
|
||||
@InterfaceAudience.Private
|
||||
|
|
|
@ -722,7 +722,7 @@ public class RMAppAttemptImpl implements RMAppAttempt, Recoverable {
|
|||
// create clientToAMToken
|
||||
appAttempt.clientToAMToken =
|
||||
new Token<ClientToAMTokenIdentifier>(new ClientToAMTokenIdentifier(
|
||||
appAttempt.applicationAttemptId),
|
||||
appAttempt.applicationAttemptId, appAttempt.user),
|
||||
appAttempt.rmContext.getClientToAMTokenSecretManager());
|
||||
}
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ public class TestRMStateStore {
|
|||
appToken.setService(new Text("appToken service"));
|
||||
|
||||
ClientToAMTokenIdentifier clientToAMTokenId =
|
||||
new ClientToAMTokenIdentifier(attemptId);
|
||||
new ClientToAMTokenIdentifier(attemptId, "user");
|
||||
clientToAMTokenMgr.registerApplication(attemptId);
|
||||
Token<ClientToAMTokenIdentifier> clientToAMToken =
|
||||
new Token<ClientToAMTokenIdentifier>(clientToAMTokenId, clientToAMTokenMgr);
|
||||
|
|
|
@ -115,7 +115,6 @@ public class TestClientToAMTokens {
|
|||
private final byte[] secretKey;
|
||||
private InetSocketAddress address;
|
||||
private boolean pinged = false;
|
||||
private ClientToAMTokenSecretManager secretManager;
|
||||
|
||||
public CustomAM(ApplicationAttemptId appId, byte[] secretKey) {
|
||||
super("CustomAM");
|
||||
|
@ -132,12 +131,14 @@ public class TestClientToAMTokens {
|
|||
protected void serviceStart() throws Exception {
|
||||
Configuration conf = getConfig();
|
||||
|
||||
secretManager = new ClientToAMTokenSecretManager(this.appAttemptId, secretKey);
|
||||
Server server;
|
||||
try {
|
||||
server =
|
||||
new RPC.Builder(conf).setProtocol(CustomProtocol.class)
|
||||
.setNumHandlers(1).setSecretManager(secretManager)
|
||||
new RPC.Builder(conf)
|
||||
.setProtocol(CustomProtocol.class)
|
||||
.setNumHandlers(1)
|
||||
.setSecretManager(
|
||||
new ClientToAMTokenSecretManager(this.appAttemptId, secretKey))
|
||||
.setInstance(this).build();
|
||||
} catch (Exception e) {
|
||||
throw new YarnRuntimeException(e);
|
||||
|
@ -146,14 +147,10 @@ public class TestClientToAMTokens {
|
|||
this.address = NetUtils.getConnectAddress(server);
|
||||
super.serviceStart();
|
||||
}
|
||||
|
||||
public ClientToAMTokenSecretManager getClientToAMTokenSecretManager() {
|
||||
return this.secretManager;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientToAMs() throws Exception {
|
||||
public void testClientToAMTokenss() throws Exception {
|
||||
|
||||
final Configuration conf = new Configuration();
|
||||
conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION,
|
||||
|
@ -204,7 +201,7 @@ public class TestClientToAMTokens {
|
|||
GetApplicationReportResponse reportResponse =
|
||||
rm.getClientRMService().getApplicationReport(request);
|
||||
ApplicationReport appReport = reportResponse.getApplicationReport();
|
||||
org.apache.hadoop.yarn.api.records.Token clientToAMToken =
|
||||
org.apache.hadoop.yarn.api.records.Token originalClientToAMToken =
|
||||
appReport.getClientToAMToken();
|
||||
|
||||
ApplicationAttemptId appAttempt = app.getCurrentAppAttempt().getAppAttemptId();
|
||||
|
@ -259,17 +256,47 @@ public class TestClientToAMTokens {
|
|||
Assert.assertFalse(am.pinged);
|
||||
}
|
||||
|
||||
// Verify denial for a malicious user
|
||||
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
|
||||
Token<ClientToAMTokenIdentifier> token =
|
||||
ConverterUtils.convertFromYarn(clientToAMToken, am.address);
|
||||
ConverterUtils.convertFromYarn(originalClientToAMToken, am.address);
|
||||
|
||||
// Verify denial for a malicious user with tampered ID
|
||||
verifyTokenWithTamperedID(conf, am, token);
|
||||
|
||||
// Verify denial for a malicious user with tampered user-name
|
||||
verifyTokenWithTamperedUserName(conf, am, token);
|
||||
|
||||
// Now for an authenticated user
|
||||
verifyValidToken(conf, am, token);
|
||||
}
|
||||
|
||||
private void verifyTokenWithTamperedID(final Configuration conf,
|
||||
final CustomAM am, Token<ClientToAMTokenIdentifier> token)
|
||||
throws IOException {
|
||||
// Malicious user, messes with appId
|
||||
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
|
||||
ClientToAMTokenIdentifier maliciousID =
|
||||
new ClientToAMTokenIdentifier(BuilderUtils.newApplicationAttemptId(
|
||||
BuilderUtils.newApplicationId(app.getApplicationId()
|
||||
.getClusterTimestamp(), 42), 43));
|
||||
BuilderUtils.newApplicationId(am.appAttemptId.getApplicationId()
|
||||
.getClusterTimestamp(), 42), 43), UserGroupInformation
|
||||
.getCurrentUser().getShortUserName());
|
||||
|
||||
verifyTamperedToken(conf, am, token, ugi, maliciousID);
|
||||
}
|
||||
|
||||
private void verifyTokenWithTamperedUserName(final Configuration conf,
|
||||
final CustomAM am, Token<ClientToAMTokenIdentifier> token)
|
||||
throws IOException {
|
||||
// Malicious user, messes with appId
|
||||
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("me");
|
||||
ClientToAMTokenIdentifier maliciousID =
|
||||
new ClientToAMTokenIdentifier(am.appAttemptId, "evilOrc");
|
||||
|
||||
verifyTamperedToken(conf, am, token, ugi, maliciousID);
|
||||
}
|
||||
|
||||
private void verifyTamperedToken(final Configuration conf, final CustomAM am,
|
||||
Token<ClientToAMTokenIdentifier> token, UserGroupInformation ugi,
|
||||
ClientToAMTokenIdentifier maliciousID) {
|
||||
Token<ClientToAMTokenIdentifier> maliciousToken =
|
||||
new Token<ClientToAMTokenIdentifier>(maliciousID.getBytes(),
|
||||
token.getPassword(), token.getKind(),
|
||||
|
@ -309,8 +336,12 @@ public class TestClientToAMTokens {
|
|||
+ "Mismatched response."));
|
||||
Assert.assertFalse(am.pinged);
|
||||
}
|
||||
}
|
||||
|
||||
// Now for an authenticated user
|
||||
private void verifyValidToken(final Configuration conf, final CustomAM am,
|
||||
Token<ClientToAMTokenIdentifier> token) throws IOException,
|
||||
InterruptedException {
|
||||
UserGroupInformation ugi;
|
||||
ugi = UserGroupInformation.createRemoteUser("me");
|
||||
ugi.addToken(token);
|
||||
|
||||
|
@ -326,5 +357,4 @@ public class TestClientToAMTokens {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue