|
@@ -35,13 +35,10 @@ import org.apache.hadoop.minikdc.MiniKdc;
|
|
|
import org.apache.hadoop.security.Credentials;
|
|
|
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.Authenticator;
|
|
|
-import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
|
|
|
-import org.apache.hadoop.security.authentication.client.PseudoAuthenticator;
|
|
|
import org.apache.hadoop.security.authorize.AuthorizationException;
|
|
|
import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
|
|
|
import org.apache.hadoop.security.token.Token;
|
|
|
+import org.apache.hadoop.test.GenericTestUtils;
|
|
|
import org.junit.After;
|
|
|
import org.junit.Assert;
|
|
|
import org.junit.Before;
|
|
@@ -73,11 +70,6 @@ import java.util.Properties;
|
|
|
import java.util.UUID;
|
|
|
import java.util.concurrent.Callable;
|
|
|
|
|
|
-import static org.mockito.Matchers.any;
|
|
|
-import static org.mockito.Mockito.doNothing;
|
|
|
-import static org.mockito.Mockito.doThrow;
|
|
|
-import static org.mockito.Mockito.mock;
|
|
|
-
|
|
|
public class TestKMS {
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(TestKMS.class);
|
|
|
|
|
@@ -262,6 +254,7 @@ public class TestKMS {
|
|
|
kdc = null;
|
|
|
}
|
|
|
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
|
|
|
+ UserGroupInformation.reset();
|
|
|
}
|
|
|
|
|
|
private <T> T doAs(String user, final PrivilegedExceptionAction<T> action)
|
|
@@ -1748,93 +1741,136 @@ public class TestKMS {
|
|
|
@Test
|
|
|
public void testDelegationTokensOpsSimple() throws Exception {
|
|
|
final Configuration conf = new Configuration();
|
|
|
- final Authenticator mock = mock(PseudoAuthenticator.class);
|
|
|
- testDelegationTokensOps(conf, mock);
|
|
|
+ testDelegationTokensOps(conf, false);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void testDelegationTokensOpsKerberized() throws Exception {
|
|
|
final Configuration conf = new Configuration();
|
|
|
conf.set("hadoop.security.authentication", "kerberos");
|
|
|
- final Authenticator mock = mock(KerberosAuthenticator.class);
|
|
|
- testDelegationTokensOps(conf, mock);
|
|
|
+ testDelegationTokensOps(conf, true);
|
|
|
}
|
|
|
|
|
|
private void testDelegationTokensOps(Configuration conf,
|
|
|
- final Authenticator mockAuthenticator) throws Exception {
|
|
|
+ final boolean useKrb) throws Exception {
|
|
|
UserGroupInformation.setConfiguration(conf);
|
|
|
File confDir = getTestDir();
|
|
|
conf = createBaseKMSConf(confDir);
|
|
|
+ if (useKrb) {
|
|
|
+ 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");
|
|
|
+ }
|
|
|
writeConf(confDir, conf);
|
|
|
- doNothing().when(mockAuthenticator).authenticate(any(URL.class),
|
|
|
- any(AuthenticatedURL.Token.class));
|
|
|
|
|
|
runServer(null, null, confDir, new KMSCallable<Void>() {
|
|
|
@Override
|
|
|
public Void call() throws Exception {
|
|
|
- Configuration conf = new Configuration();
|
|
|
- URI uri = createKMSUri(getKMSUrl());
|
|
|
- KeyProvider kp = createProvider(uri, conf);
|
|
|
- conf.set(KeyProviderFactory.KEY_PROVIDER_PATH,
|
|
|
+ final Configuration clientConf = new Configuration();
|
|
|
+ final URI uri = createKMSUri(getKMSUrl());
|
|
|
+ clientConf.set(KeyProviderFactory.KEY_PROVIDER_PATH,
|
|
|
createKMSUri(getKMSUrl()).toString());
|
|
|
|
|
|
- // test delegation token retrieval
|
|
|
- KeyProviderDelegationTokenExtension kpdte =
|
|
|
- KeyProviderDelegationTokenExtension.
|
|
|
- createKeyProviderDelegationTokenExtension(kp);
|
|
|
- Credentials credentials = new Credentials();
|
|
|
- final Token<?>[] tokens = kpdte.addDelegationTokens(
|
|
|
- UserGroupInformation.getCurrentUser().getUserName(), credentials);
|
|
|
- Assert.assertEquals(1, credentials.getAllTokens().size());
|
|
|
- InetSocketAddress kmsAddr = new InetSocketAddress(getKMSUrl().getHost(),
|
|
|
- getKMSUrl().getPort());
|
|
|
- Assert.assertEquals(KMSClientProvider.TOKEN_KIND,
|
|
|
- credentials.getToken(SecurityUtil.buildTokenService(kmsAddr)).
|
|
|
- getKind());
|
|
|
-
|
|
|
- // After this point, we're supposed to use the delegation token to auth.
|
|
|
- doThrow(new IOException("Authenticator should not fall back"))
|
|
|
- .when(mockAuthenticator).authenticate(any(URL.class),
|
|
|
- any(AuthenticatedURL.Token.class));
|
|
|
-
|
|
|
- // test delegation token renewal
|
|
|
- boolean renewed = false;
|
|
|
- for (Token<?> token : tokens) {
|
|
|
- if (!(token.getKind().equals(KMSClientProvider.TOKEN_KIND))) {
|
|
|
- LOG.info("Skipping token {}", token);
|
|
|
- continue;
|
|
|
- }
|
|
|
- LOG.info("Got dt for " + uri + "; " + token);
|
|
|
- long tokenLife = token.renew(conf);
|
|
|
- LOG.info("Renewed token of kind {}, new lifetime:{}",
|
|
|
- token.getKind(), tokenLife);
|
|
|
- Thread.sleep(100);
|
|
|
- long newTokenLife = token.renew(conf);
|
|
|
- LOG.info("Renewed token of kind {}, new lifetime:{}",
|
|
|
- token.getKind(), newTokenLife);
|
|
|
- Assert.assertTrue(newTokenLife > tokenLife);
|
|
|
- renewed = true;
|
|
|
- }
|
|
|
- Assert.assertTrue(renewed);
|
|
|
+ doAs("client", new PrivilegedExceptionAction<Void>() {
|
|
|
+ @Override
|
|
|
+ public Void run() throws Exception {
|
|
|
+ KeyProvider kp = createProvider(uri, clientConf);
|
|
|
+ // test delegation token retrieval
|
|
|
+ KeyProviderDelegationTokenExtension kpdte =
|
|
|
+ KeyProviderDelegationTokenExtension.
|
|
|
+ createKeyProviderDelegationTokenExtension(kp);
|
|
|
+ final Credentials credentials = new Credentials();
|
|
|
+ final Token<?>[] tokens =
|
|
|
+ kpdte.addDelegationTokens("client1", credentials);
|
|
|
+ Assert.assertEquals(1, credentials.getAllTokens().size());
|
|
|
+ InetSocketAddress kmsAddr =
|
|
|
+ new InetSocketAddress(getKMSUrl().getHost(),
|
|
|
+ getKMSUrl().getPort());
|
|
|
+ Assert.assertEquals(KMSClientProvider.TOKEN_KIND,
|
|
|
+ credentials.getToken(SecurityUtil.buildTokenService(kmsAddr)).
|
|
|
+ getKind());
|
|
|
+
|
|
|
+ // Test non-renewer user cannot renew.
|
|
|
+ for (Token<?> token : tokens) {
|
|
|
+ if (!(token.getKind().equals(KMSClientProvider.TOKEN_KIND))) {
|
|
|
+ LOG.info("Skipping token {}", token);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ LOG.info("Got dt for " + uri + "; " + token);
|
|
|
+ try {
|
|
|
+ token.renew(clientConf);
|
|
|
+ Assert.fail("client should not be allowed to renew token with"
|
|
|
+ + "renewer=client1");
|
|
|
+ } catch (Exception e) {
|
|
|
+ GenericTestUtils.assertExceptionContains(
|
|
|
+ "tries to renew a token with renewer", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // test delegation token cancellation
|
|
|
- for (Token<?> token : tokens) {
|
|
|
- if (!(token.getKind().equals(KMSClientProvider.TOKEN_KIND))) {
|
|
|
- LOG.info("Skipping token {}", token);
|
|
|
- continue;
|
|
|
- }
|
|
|
- LOG.info("Got dt for " + uri + "; " + token);
|
|
|
- token.cancel(conf);
|
|
|
- LOG.info("Cancelled token of kind {}", token.getKind());
|
|
|
- doNothing().when(mockAuthenticator).
|
|
|
- authenticate(any(URL.class), any(AuthenticatedURL.Token.class));
|
|
|
- try {
|
|
|
- token.renew(conf);
|
|
|
- Assert.fail("should not be able to renew a canceled token");
|
|
|
- } catch (Exception e) {
|
|
|
- LOG.info("Expected exception when trying to renew token", e);
|
|
|
+ final UserGroupInformation otherUgi;
|
|
|
+ if (useKrb) {
|
|
|
+ UserGroupInformation
|
|
|
+ .loginUserFromKeytab("client1", keytab.getAbsolutePath());
|
|
|
+ otherUgi = UserGroupInformation.getLoginUser();
|
|
|
+ } else {
|
|
|
+ otherUgi = UserGroupInformation.createUserForTesting("client1",
|
|
|
+ new String[] {"other group"});
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // test delegation token renewal via renewer
|
|
|
+ otherUgi.doAs(new PrivilegedExceptionAction<Void>() {
|
|
|
+ @Override
|
|
|
+ public Void run() throws Exception {
|
|
|
+ boolean renewed = false;
|
|
|
+ for (Token<?> token : tokens) {
|
|
|
+ if (!(token.getKind()
|
|
|
+ .equals(KMSClientProvider.TOKEN_KIND))) {
|
|
|
+ LOG.info("Skipping token {}", token);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ LOG.info("Got dt for " + uri + "; " + token);
|
|
|
+ long tokenLife = token.renew(clientConf);
|
|
|
+ LOG.info("Renewed token of kind {}, new lifetime:{}",
|
|
|
+ token.getKind(), tokenLife);
|
|
|
+ Thread.sleep(100);
|
|
|
+ long newTokenLife = token.renew(clientConf);
|
|
|
+ LOG.info("Renewed token of kind {}, new lifetime:{}",
|
|
|
+ token.getKind(), newTokenLife);
|
|
|
+ Assert.assertTrue(newTokenLife > tokenLife);
|
|
|
+ renewed = true;
|
|
|
+ }
|
|
|
+ Assert.assertTrue(renewed);
|
|
|
+
|
|
|
+ // test delegation token cancellation
|
|
|
+ for (Token<?> token : tokens) {
|
|
|
+ if (!(token.getKind()
|
|
|
+ .equals(KMSClientProvider.TOKEN_KIND))) {
|
|
|
+ LOG.info("Skipping token {}", token);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ LOG.info("Got dt for " + uri + "; " + token);
|
|
|
+ token.cancel(clientConf);
|
|
|
+ LOG.info("Cancelled token of kind {}", token.getKind());
|
|
|
+ try {
|
|
|
+ token.renew(clientConf);
|
|
|
+ Assert
|
|
|
+ .fail("should not be able to renew a canceled token");
|
|
|
+ } catch (Exception e) {
|
|
|
+ LOG.info("Expected exception when renewing token", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return null;
|
|
|
+ } finally {
|
|
|
+ otherUgi.logoutUserFromKeytab();
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
+ });
|
|
|
return null;
|
|
|
}
|
|
|
});
|