YARN-2232. Fixed ResourceManager to allow DelegationToken owners to be able to cancel their own tokens in secure mode. Contributed by Varun Vasudev.

svn merge --ignore-ancestry -c 1607484 ../../trunk/


git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1607485 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Vinod Kumar Vavilapalli 2014-07-02 21:37:20 +00:00
parent 99bced167b
commit 0ac01d7cfc
3 changed files with 162 additions and 2 deletions

View File

@ -309,6 +309,9 @@ Release 2.5.0 - UNRELEASED
YARN-2216 YARN-2065 AM cannot create new containers after restart
(Jian He via stevel)
YARN-2232. Fixed ResourceManager to allow DelegationToken owners to be able
to cancel their own tokens in secure mode. (Varun Vasudev via vinodkv)
Release 2.4.1 - 2014-06-23
INCOMPATIBLE CHANGES

View File

@ -918,7 +918,7 @@ public CancelDelegationTokenResponse cancelDelegationToken(
protoToken.getIdentifier().array(), protoToken.getPassword().array(),
new Text(protoToken.getKind()), new Text(protoToken.getService()));
String user = getRenewerForToken(token);
String user = UserGroupInformation.getCurrentUser().getUserName();
rmDTSecretManager.cancelToken(token, user);
return Records.newRecord(CancelDelegationTokenResponse.class);
} catch (IOException e) {

View File

@ -44,16 +44,17 @@
import java.util.concurrent.CyclicBarrier;
import org.junit.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.yarn.MockApps;
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
import org.apache.hadoop.yarn.api.protocolrecords.ApplicationsRequestScope;
import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportResponse;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptsRequest;
@ -138,6 +139,10 @@ public class TestClientRMService {
private final static String QUEUE_1 = "Q-1";
private final static String QUEUE_2 = "Q-2";
private final static String kerberosRule = "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT";
static {
KerberosName.setRules(kerberosRule);
}
@BeforeClass
public static void setupSecretManager() throws IOException {
@ -479,6 +484,17 @@ public void testGetQueueInfo() throws Exception {
UserGroupInformation.createRemoteUser("owner");
private static final UserGroupInformation other =
UserGroupInformation.createRemoteUser("other");
private static final UserGroupInformation tester =
UserGroupInformation.createRemoteUser("tester");
private static final String testerPrincipal = "tester@EXAMPLE.COM";
private static final String ownerPrincipal = "owner@EXAMPLE.COM";
private static final String otherPrincipal = "other@EXAMPLE.COM";
private static final UserGroupInformation testerKerb =
UserGroupInformation.createRemoteUser(testerPrincipal);
private static final UserGroupInformation ownerKerb =
UserGroupInformation.createRemoteUser(ownerPrincipal);
private static final UserGroupInformation otherKerb =
UserGroupInformation.createRemoteUser(otherPrincipal);
@Test
public void testTokenRenewalByOwner() throws Exception {
@ -546,6 +562,147 @@ private void checkTokenRenewal(UserGroupInformation owner,
rmService.renewDelegationToken(request);
}
@Test
public void testTokenCancellationByOwner() throws Exception {
// two tests required - one with a kerberos name
// and with a short name
RMContext rmContext = mock(RMContext.class);
final ClientRMService rmService =
new ClientRMService(rmContext, null, null, null, null, dtsm);
testerKerb.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
checkTokenCancellation(rmService, testerKerb, other);
return null;
}
});
owner.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
checkTokenCancellation(owner, other);
return null;
}
});
}
@Test
public void testTokenCancellationByRenewer() throws Exception {
// two tests required - one with a kerberos name
// and with a short name
RMContext rmContext = mock(RMContext.class);
final ClientRMService rmService =
new ClientRMService(rmContext, null, null, null, null, dtsm);
testerKerb.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
checkTokenCancellation(rmService, owner, testerKerb);
return null;
}
});
other.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
checkTokenCancellation(owner, other);
return null;
}
});
}
@Test
public void testTokenCancellationByWrongUser() {
// two sets to test -
// 1. try to cancel tokens of short and kerberos users as a kerberos UGI
// 2. try to cancel tokens of short and kerberos users as a simple auth UGI
RMContext rmContext = mock(RMContext.class);
final ClientRMService rmService =
new ClientRMService(rmContext, null, null, null, null, dtsm);
UserGroupInformation[] kerbTestOwners =
{ owner, other, tester, ownerKerb, otherKerb };
UserGroupInformation[] kerbTestRenewers =
{ owner, other, ownerKerb, otherKerb };
for (final UserGroupInformation tokOwner : kerbTestOwners) {
for (final UserGroupInformation tokRenewer : kerbTestRenewers) {
try {
testerKerb.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
try {
checkTokenCancellation(rmService, tokOwner, tokRenewer);
Assert.fail("We should not reach here; token owner = "
+ tokOwner.getUserName() + ", renewer = "
+ tokRenewer.getUserName());
return null;
} catch (YarnException e) {
Assert.assertTrue(e.getMessage().contains(
testerKerb.getUserName()
+ " is not authorized to cancel the token"));
return null;
}
}
});
} catch (Exception e) {
Assert.fail("Unexpected exception; " + e.getMessage());
}
}
}
UserGroupInformation[] simpleTestOwners =
{ owner, other, ownerKerb, otherKerb, testerKerb };
UserGroupInformation[] simpleTestRenewers =
{ owner, other, ownerKerb, otherKerb };
for (final UserGroupInformation tokOwner : simpleTestOwners) {
for (final UserGroupInformation tokRenewer : simpleTestRenewers) {
try {
tester.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
try {
checkTokenCancellation(tokOwner, tokRenewer);
Assert.fail("We should not reach here; token owner = "
+ tokOwner.getUserName() + ", renewer = "
+ tokRenewer.getUserName());
return null;
} catch (YarnException ex) {
Assert.assertTrue(ex.getMessage().contains(
tester.getUserName()
+ " is not authorized to cancel the token"));
return null;
}
}
});
} catch (Exception e) {
Assert.fail("Unexpected exception; " + e.getMessage());
}
}
}
}
private void checkTokenCancellation(UserGroupInformation owner,
UserGroupInformation renewer) throws IOException, YarnException {
RMContext rmContext = mock(RMContext.class);
final ClientRMService rmService =
new ClientRMService(rmContext, null, null, null, null, dtsm);
checkTokenCancellation(rmService, owner, renewer);
}
private void checkTokenCancellation(ClientRMService rmService,
UserGroupInformation owner, UserGroupInformation renewer)
throws IOException, YarnException {
RMDelegationTokenIdentifier tokenIdentifier =
new RMDelegationTokenIdentifier(new Text(owner.getUserName()),
new Text(renewer.getUserName()), null);
Token<?> token =
new Token<RMDelegationTokenIdentifier>(tokenIdentifier, dtsm);
org.apache.hadoop.yarn.api.records.Token dToken =
BuilderUtils.newDelegationToken(token.getIdentifier(), token.getKind()
.toString(), token.getPassword(), token.getService().toString());
CancelDelegationTokenRequest request =
Records.newRecord(CancelDelegationTokenRequest.class);
request.setDelegationToken(dToken);
rmService.cancelDelegationToken(request);
}
@Test (timeout = 30000)
@SuppressWarnings ("rawtypes")
public void testAppSubmit() throws Exception {