YARN-2232. Fixed ResourceManager to allow DelegationToken owners to be able to cancel their own tokens in secure mode. Contributed by Varun Vasudev.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1607484 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
447c1c233b
commit
45b191e38c
|
@ -328,6 +328,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
|
||||
|
|
|
@ -919,7 +919,7 @@ public class ClientRMService extends AbstractService implements
|
|||
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) {
|
||||
|
|
|
@ -44,16 +44,17 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
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 class TestClientRMService {
|
|||
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 @@ public class TestClientRMService {
|
|||
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 {
|
||||
|
|
Loading…
Reference in New Issue