Fix NodeManager to verify the application's user-name.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1390825 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Vinod Kumar Vavilapalli 2012-09-27 03:43:57 +00:00
parent 47dfcf45af
commit 40062e1aaa
8 changed files with 68 additions and 25 deletions

View File

@ -48,14 +48,16 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
private ContainerId containerId;
private String nmHostAddr;
private String appSubmitter;
private Resource resource;
private long expiryTimeStamp;
private int masterKeyId;
public ContainerTokenIdentifier(ContainerId containerID, String hostName,
Resource r, long expiryTimeStamp, int masterKeyId) {
String appSubmitter, Resource r, long expiryTimeStamp, int masterKeyId) {
this.containerId = containerID;
this.nmHostAddr = hostName;
this.appSubmitter = appSubmitter;
this.resource = r;
this.expiryTimeStamp = expiryTimeStamp;
this.masterKeyId = masterKeyId;
@ -71,6 +73,10 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
return this.containerId;
}
public String getApplicationSubmitter() {
return this.appSubmitter;
}
public String getNmHostAddress() {
return this.nmHostAddr;
}
@ -98,6 +104,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
out.writeInt(applicationAttemptId.getAttemptId());
out.writeInt(this.containerId.getId());
out.writeUTF(this.nmHostAddr);
out.writeUTF(this.appSubmitter);
out.writeInt(this.resource.getMemory());
out.writeLong(this.expiryTimeStamp);
out.writeInt(this.masterKeyId);
@ -112,6 +119,7 @@ public class ContainerTokenIdentifier extends TokenIdentifier {
this.containerId = BuilderUtils.newContainerId(applicationAttemptId, in
.readInt());
this.nmHostAddr = in.readUTF();
this.appSubmitter = in.readUTF();
this.resource = BuilderUtils.newResource(in.readInt());
this.expiryTimeStamp = in.readLong();
this.masterKeyId = in.readInt();

View File

@ -128,7 +128,8 @@ public class BaseContainerTokenSecretManager extends
public byte[] createPassword(ContainerTokenIdentifier identifier) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating password for " + identifier.getContainerID()
+ " to be run on NM " + identifier.getNmHostAddress());
+ " for user " + identifier.getUser() + " to be run on NM "
+ identifier.getNmHostAddress());
}
this.readLock.lock();
try {
@ -155,7 +156,8 @@ public class BaseContainerTokenSecretManager extends
throws org.apache.hadoop.security.token.SecretManager.InvalidToken {
if (LOG.isDebugEnabled()) {
LOG.debug("Retrieving password for " + identifier.getContainerID()
+ " to be run on NM " + identifier.getNmHostAddress());
+ " for user " + identifier.getUser() + " to be run on NM "
+ identifier.getNmHostAddress());
}
return createPassword(identifier.getBytes(), masterKey.getSecretKey());
}
@ -173,11 +175,12 @@ public class BaseContainerTokenSecretManager extends
*
* @param containerId
* @param nodeId
* @param appSubmitter
* @param capability
* @return the container-token
*/
public ContainerToken createContainerToken(ContainerId containerId,
NodeId nodeId, Resource capability) {
NodeId nodeId, String appSubmitter, Resource capability) {
byte[] password;
ContainerTokenIdentifier tokenIdentifier;
long expiryTimeStamp =
@ -188,8 +191,8 @@ public class BaseContainerTokenSecretManager extends
try {
tokenIdentifier =
new ContainerTokenIdentifier(containerId, nodeId.toString(),
capability, expiryTimeStamp, this.currentMasterKey.getMasterKey()
.getKeyId());
appSubmitter, capability, expiryTimeStamp, this.currentMasterKey
.getMasterKey().getKeyId());
password = this.createPassword(tokenIdentifier);
} finally {

View File

@ -329,7 +329,6 @@ public class ContainerManagerImpl extends CompositeService implements
+ remoteUgi.getTokenIdentifiers().size());
}
// Get the tokenId from the remote user ugi
ContainerTokenIdentifier tokenId =
selectContainerTokenIdentifier(remoteUgi);
@ -341,8 +340,16 @@ public class ContainerManagerImpl extends CompositeService implements
+ containerIDStr);
} else {
// Is the container coming in with correct user-name?
if (!tokenId.getApplicationSubmitter().equals(launchContext.getUser())) {
unauthorized = true;
messageBuilder.append("\n Expected user-name "
+ tokenId.getApplicationSubmitter() + " but found "
+ launchContext.getUser());
}
// Is the container being relaunched? Or RPC layer let startCall with
// tokens generated off old-secret through
// tokens generated off old-secret through?
if (!this.context.getContainerTokenSecretManager()
.isValidStartContainerRequest(tokenId)) {
unauthorized = true;

View File

@ -231,7 +231,6 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
RMApp application = null;
try {
String clientTokenStr = null;
String user = UserGroupInformation.getCurrentUser().getShortUserName();
if (UserGroupInformation.isSecurityEnabled()) {
Token<ClientTokenIdentifier> clientToken = new
Token<ClientTokenIdentifier>(
@ -256,11 +255,12 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent> {
submissionContext);
// Create RMApp
application = new RMAppImpl(applicationId, rmContext,
this.conf, submissionContext.getApplicationName(), user,
submissionContext.getQueue(), submissionContext, clientTokenStr,
appStore, this.scheduler,
this.masterService, submitTime);
application =
new RMAppImpl(applicationId, rmContext, this.conf,
submissionContext.getApplicationName(),
submissionContext.getUser(), submissionContext.getQueue(),
submissionContext, clientTokenStr, appStore, this.scheduler,
this.masterService, submitTime);
// Sanity check - duplicate?
if (rmContext.getRMApps().putIfAbsent(applicationId, application) !=

View File

@ -1197,7 +1197,7 @@ public class LeafQueue implements CSQueue {
if (UserGroupInformation.isSecurityEnabled()) {
containerToken =
containerTokenSecretManager.createContainerToken(containerId, nodeId,
capability);
application.getUser(), capability);
if (containerToken == null) {
return null; // Try again later.
}

View File

@ -161,7 +161,7 @@ public class AppSchedulable extends Schedulable {
if (UserGroupInformation.isSecurityEnabled()) {
containerToken =
containerTokenSecretManager.createContainerToken(containerId, nodeId,
capability);
application.getUser(), capability);
if (containerToken == null) {
return null; // Try again later.
}

View File

@ -539,7 +539,8 @@ public class FifoScheduler implements ResourceScheduler, Configurable {
if (UserGroupInformation.isSecurityEnabled()) {
containerToken =
this.rmContext.getContainerTokenSecretManager()
.createContainerToken(containerId, nodeId, capability);
.createContainerToken(containerId, nodeId,
application.getUser(), capability);
if (containerToken == null) {
return i; // Try again later.
}

View File

@ -219,9 +219,10 @@ public class TestContainerManagerSecurity {
// Malice user modifies the resource amount
Resource modifiedResource = BuilderUtils.newResource(2048);
ContainerTokenIdentifier modifiedIdentifier = new ContainerTokenIdentifier(
dummyIdentifier.getContainerID(), dummyIdentifier.getNmHostAddress(),
modifiedResource, Long.MAX_VALUE, dummyIdentifier.getMasterKeyId());
ContainerTokenIdentifier modifiedIdentifier =
new ContainerTokenIdentifier(dummyIdentifier.getContainerID(),
dummyIdentifier.getNmHostAddress(), "testUser", modifiedResource,
Long.MAX_VALUE, dummyIdentifier.getMasterKeyId());
Token<ContainerTokenIdentifier> modifiedToken = new Token<ContainerTokenIdentifier>(
modifiedIdentifier.getBytes(), containerToken.getPassword().array(),
new Text(containerToken.getKind()), new Text(containerToken
@ -320,12 +321,14 @@ public class TestContainerManagerSecurity {
callWithIllegalContainerID(client, tokenId);
callWithIllegalResource(client, tokenId);
callWithIllegalUserName(client, tokenId);
return client;
}
});
/////////// End of testing for illegal containerIDs and illegal Resources
// ///////// End of testing for illegal containerIDs, illegal Resources and
// illegal users
/////////// Test calls with expired tokens
RPC.stopProxy(client);
@ -336,7 +339,7 @@ public class TestContainerManagerSecurity {
resourceManager.getRMContainerTokenSecretManager();
final ContainerTokenIdentifier newTokenId =
new ContainerTokenIdentifier(tokenId.getContainerID(),
tokenId.getNmHostAddress(), tokenId.getResource(),
tokenId.getNmHostAddress(), "testUser", tokenId.getResource(),
System.currentTimeMillis() - 1,
containerTokenSecreteManager.getCurrentKey().getKeyId());
byte[] passowrd =
@ -346,9 +349,7 @@ public class TestContainerManagerSecurity {
token = new Token<ContainerTokenIdentifier>(
newTokenId.getBytes(), passowrd, new Text(
containerToken.getKind()), new Text(containerToken.getService()));
unauthorizedUser.addToken(token);
unauthorizedUser.doAs(new PrivilegedAction<Void>() {
@Override
@ -567,6 +568,29 @@ public class TestContainerManagerSecurity {
}
}
void callWithIllegalUserName(ContainerManager client,
ContainerTokenIdentifier tokenId) {
StartContainerRequest request = recordFactory
.newRecordInstance(StartContainerRequest.class);
// Authenticated but unauthorized, due to wrong resource
ContainerLaunchContext context =
createContainerLaunchContextForTest(tokenId);
context.setUser("Saruman"); // Set a different user-name.
request.setContainerLaunchContext(context);
try {
client.startContainer(request);
fail("Connection initiation with unauthorized "
+ "access is expected to fail.");
} catch (YarnRemoteException e) {
LOG.info("Got exception : ", e);
Assert.assertTrue(e.getMessage().contains(
"Unauthorized request to start container. "));
Assert.assertTrue(e.getMessage().contains(
"Expected user-name " + tokenId.getApplicationSubmitter()
+ " but found " + context.getUser()));
}
}
private ContainerLaunchContext createContainerLaunchContextForTest(
ContainerTokenIdentifier tokenId) {
ContainerLaunchContext context =