HADOOP-13255. KMSClientProvider should check and renew tgt when doing delegation token operations. Contributed by Xiao Chen.

This commit is contained in:
Xiaoyu Yao 2016-06-16 15:22:00 -07:00
parent 127d2c7281
commit b1674caa40
6 changed files with 95 additions and 16 deletions

View File

@ -536,8 +536,6 @@ private HttpURLConnection createConnection(final URL url, String method)
UserGroupInformation.AuthenticationMethod.PROXY) UserGroupInformation.AuthenticationMethod.PROXY)
? currentUgi.getShortUserName() : null; ? currentUgi.getShortUserName() : null;
// check and renew TGT to handle potential expiration
actualUgi.checkTGTAndReloginFromKeytab();
// creating the HTTP connection using the current UGI at constructor time // creating the HTTP connection using the current UGI at constructor time
conn = actualUgi.doAs(new PrivilegedExceptionAction<HttpURLConnection>() { conn = actualUgi.doAs(new PrivilegedExceptionAction<HttpURLConnection>() {
@Override @Override

View File

@ -103,7 +103,7 @@ public class UserGroupInformation {
* @param immediate true if we should login without waiting for ticket window * @param immediate true if we should login without waiting for ticket window
*/ */
@VisibleForTesting @VisibleForTesting
static void setShouldRenewImmediatelyForTests(boolean immediate) { public static void setShouldRenewImmediatelyForTests(boolean immediate) {
shouldRenewImmediatelyForTests = immediate; shouldRenewImmediatelyForTests = immediate;
} }

View File

@ -20,6 +20,7 @@
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticatedURL; import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
import org.apache.hadoop.security.authentication.client.AuthenticationException; import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.Authenticator; import org.apache.hadoop.security.authentication.client.Authenticator;
@ -143,6 +144,8 @@ private void appendDelegationToken(final AuthenticatedURL.Token token,
public void authenticate(URL url, AuthenticatedURL.Token token) public void authenticate(URL url, AuthenticatedURL.Token token)
throws IOException, AuthenticationException { throws IOException, AuthenticationException {
if (!hasDelegationToken(url, token)) { if (!hasDelegationToken(url, token)) {
// check and renew TGT to handle potential expiration
UserGroupInformation.getCurrentUser().checkTGTAndReloginFromKeytab();
authenticator.authenticate(url, token); authenticator.authenticate(url, token);
} }
} }

View File

@ -42,12 +42,9 @@
import org.apache.hadoop.security.authorize.AuthorizationException; import org.apache.hadoop.security.authorize.AuthorizationException;
import org.apache.hadoop.security.ssl.KeyStoreTestUtil; import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.test.GenericTestUtils; import org.junit.After;
import org.apache.log4j.Level;
import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.Timeout; import org.junit.rules.Timeout;
@ -88,11 +85,11 @@ public class TestKMS {
public final Timeout testTimeout = new Timeout(180000); public final Timeout testTimeout = new Timeout(180000);
@Before @Before
public void cleanUp() { public void setUp() throws Exception {
setUpMiniKdc();
// resetting kerberos security // resetting kerberos security
Configuration conf = new Configuration(); Configuration conf = new Configuration();
UserGroupInformation.setConfiguration(conf); UserGroupInformation.setConfiguration(conf);
GenericTestUtils.setLogLevel(LOG, Level.INFO);
} }
public static File getTestDir() throws Exception { public static File getTestDir() throws Exception {
@ -232,10 +229,8 @@ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
private static MiniKdc kdc; private static MiniKdc kdc;
private static File keytab; private static File keytab;
@BeforeClass private static void setUpMiniKdc(Properties kdcConf) throws Exception {
public static void setUpMiniKdc() throws Exception {
File kdcDir = getTestDir(); File kdcDir = getTestDir();
Properties kdcConf = MiniKdc.createConf();
kdc = new MiniKdc(kdcConf, kdcDir); kdc = new MiniKdc(kdcConf, kdcDir);
kdc.start(); kdc.start();
keytab = new File(kdcDir, "keytab"); keytab = new File(kdcDir, "keytab");
@ -255,11 +250,18 @@ public static void setUpMiniKdc() throws Exception {
principals.toArray(new String[principals.size()])); principals.toArray(new String[principals.size()]));
} }
@AfterClass private void setUpMiniKdc() throws Exception {
public static void tearDownMiniKdc() throws Exception { Properties kdcConf = MiniKdc.createConf();
setUpMiniKdc(kdcConf);
}
@After
public void tearDownMiniKdc() throws Exception {
if (kdc != null) { if (kdc != null) {
kdc.stop(); kdc.stop();
kdc = null;
} }
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
} }
private <T> T doAs(String user, final PrivilegedExceptionAction<T> action) private <T> T doAs(String user, final PrivilegedExceptionAction<T> action)
@ -2053,6 +2055,73 @@ public void testWebHDFSProxyUserSimple() throws Exception {
doWebHDFSProxyUserTest(false); doWebHDFSProxyUserTest(false);
} }
@Test
public void testTGTRenewal() throws Exception {
tearDownMiniKdc();
Properties kdcConf = MiniKdc.createConf();
kdcConf.setProperty(MiniKdc.MAX_TICKET_LIFETIME, "3");
kdcConf.setProperty(MiniKdc.MIN_TICKET_LIFETIME, "3");
setUpMiniKdc(kdcConf);
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
final File testDir = getTestDir();
conf = createBaseKMSConf(testDir);
conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath());
conf.set("hadoop.kms.authentication.kerberos.principal", "HTTP/localhost");
conf.set("hadoop.kms.authentication.kerberos.name.rules", "DEFAULT");
conf.set("hadoop.kms.proxyuser.client.users", "*");
conf.set("hadoop.kms.proxyuser.client.hosts", "*");
writeConf(testDir, conf);
runServer(null, null, testDir, new KMSCallable<Void>() {
@Override
public Void call() throws Exception {
final Configuration conf = new Configuration();
final URI uri = createKMSUri(getKMSUrl());
UserGroupInformation.setShouldRenewImmediatelyForTests(true);
UserGroupInformation
.loginUserFromKeytab("client", keytab.getAbsolutePath());
final UserGroupInformation clientUgi =
UserGroupInformation.getCurrentUser();
clientUgi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
// Verify getKeys can relogin
Thread.sleep(3100);
KeyProvider kp = createProvider(uri, conf);
kp.getKeys();
// Verify addDelegationTokens can relogin
// (different code path inside KMSClientProvider than getKeys)
Thread.sleep(3100);
kp = createProvider(uri, conf);
((KeyProviderDelegationTokenExtension.DelegationTokenExtension) kp)
.addDelegationTokens("myuser", new Credentials());
// Verify getKeys can relogin with proxy user
UserGroupInformation anotherUgi =
UserGroupInformation.createProxyUser("client1", clientUgi);
anotherUgi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
Thread.sleep(3100);
KeyProvider kp = createProvider(uri, conf);
kp.getKeys();
return null;
}
});
return null;
}
});
return null;
}
});
}
public void doWebHDFSProxyUserTest(final boolean kerberos) throws Exception { public void doWebHDFSProxyUserTest(final boolean kerberos) throws Exception {
Configuration conf = new Configuration(); Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos"); conf.set("hadoop.security.authentication", "kerberos");

View File

@ -22,7 +22,7 @@ log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{1} - %m%n log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{1} - %m%n
log4j.rootLogger=WARN, stdout log4j.rootLogger=INFO, stdout
log4j.logger.org.apache.hadoop.conf=ERROR log4j.logger.org.apache.hadoop.conf=ERROR
log4j.logger.org.apache.hadoop.crytpo.key.kms.server=ALL log4j.logger.org.apache.hadoop.crytpo.key.kms.server=ALL
log4j.logger.com.sun.jersey.server.wadl.generators.WadlGeneratorJAXBGrammarGenerator=OFF log4j.logger.com.sun.jersey.server.wadl.generators.WadlGeneratorJAXBGrammarGenerator=OFF

View File

@ -147,6 +147,7 @@ public void run() {
public static final String KDC_PORT = "kdc.port"; public static final String KDC_PORT = "kdc.port";
public static final String INSTANCE = "instance"; public static final String INSTANCE = "instance";
public static final String MAX_TICKET_LIFETIME = "max.ticket.lifetime"; public static final String MAX_TICKET_LIFETIME = "max.ticket.lifetime";
public static final String MIN_TICKET_LIFETIME = "min.ticket.lifetime";
public static final String MAX_RENEWABLE_LIFETIME = "max.renewable.lifetime"; public static final String MAX_RENEWABLE_LIFETIME = "max.renewable.lifetime";
public static final String TRANSPORT = "transport"; public static final String TRANSPORT = "transport";
public static final String DEBUG = "debug"; public static final String DEBUG = "debug";
@ -280,7 +281,7 @@ public synchronized void start() throws Exception {
simpleKdc.init(); simpleKdc.init();
resetDefaultRealm(); resetDefaultRealm();
simpleKdc.start(); simpleKdc.start();
LOG.info("MiniKdc stated."); LOG.info("MiniKdc started.");
} }
private void resetDefaultRealm() throws IOException { private void resetDefaultRealm() throws IOException {
@ -321,6 +322,14 @@ private void prepareKdcServer() throws Exception {
if (conf.getProperty(DEBUG) != null) { if (conf.getProperty(DEBUG) != null) {
krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG)); krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG));
} }
if (conf.getProperty(MIN_TICKET_LIFETIME) != null) {
simpleKdc.getKdcConfig().setLong(KdcConfigKey.MINIMUM_TICKET_LIFETIME,
Long.parseLong(conf.getProperty(MIN_TICKET_LIFETIME)));
}
if (conf.getProperty(MAX_TICKET_LIFETIME) != null) {
simpleKdc.getKdcConfig().setLong(KdcConfigKey.MAXIMUM_TICKET_LIFETIME,
Long.parseLong(conf.getProperty(MiniKdc.MAX_TICKET_LIFETIME)));
}
} }
/** /**