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
|
YARN-2216 YARN-2065 AM cannot create new containers after restart
|
||||||
(Jian He via stevel)
|
(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
|
Release 2.4.1 - 2014-06-23
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
@ -919,7 +919,7 @@ public CancelDelegationTokenResponse cancelDelegationToken(
|
|||||||
protoToken.getIdentifier().array(), protoToken.getPassword().array(),
|
protoToken.getIdentifier().array(), protoToken.getPassword().array(),
|
||||||
new Text(protoToken.getKind()), new Text(protoToken.getService()));
|
new Text(protoToken.getKind()), new Text(protoToken.getService()));
|
||||||
|
|
||||||
String user = getRenewerForToken(token);
|
String user = UserGroupInformation.getCurrentUser().getUserName();
|
||||||
rmDTSecretManager.cancelToken(token, user);
|
rmDTSecretManager.cancelToken(token, user);
|
||||||
return Records.newRecord(CancelDelegationTokenResponse.class);
|
return Records.newRecord(CancelDelegationTokenResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -44,16 +44,17 @@
|
|||||||
import java.util.concurrent.CyclicBarrier;
|
import java.util.concurrent.CyclicBarrier;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.io.Text;
|
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.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
import org.apache.hadoop.yarn.MockApps;
|
import org.apache.hadoop.yarn.MockApps;
|
||||||
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
|
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.ApplicationsRequestScope;
|
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.GetApplicationAttemptReportRequest;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportResponse;
|
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportResponse;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptsRequest;
|
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_1 = "Q-1";
|
||||||
private final static String QUEUE_2 = "Q-2";
|
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
|
@BeforeClass
|
||||||
public static void setupSecretManager() throws IOException {
|
public static void setupSecretManager() throws IOException {
|
||||||
@ -479,6 +484,17 @@ public void testGetQueueInfo() throws Exception {
|
|||||||
UserGroupInformation.createRemoteUser("owner");
|
UserGroupInformation.createRemoteUser("owner");
|
||||||
private static final UserGroupInformation other =
|
private static final UserGroupInformation other =
|
||||||
UserGroupInformation.createRemoteUser("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
|
@Test
|
||||||
public void testTokenRenewalByOwner() throws Exception {
|
public void testTokenRenewalByOwner() throws Exception {
|
||||||
@ -546,6 +562,147 @@ private void checkTokenRenewal(UserGroupInformation owner,
|
|||||||
rmService.renewDelegationToken(request);
|
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)
|
@Test (timeout = 30000)
|
||||||
@SuppressWarnings ("rawtypes")
|
@SuppressWarnings ("rawtypes")
|
||||||
public void testAppSubmit() throws Exception {
|
public void testAppSubmit() throws Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user