|
@@ -20,20 +20,37 @@ package org.apache.hadoop.hdfs.web;
|
|
|
|
|
|
import static org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod.KERBEROS;
|
|
|
import static org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod.SIMPLE;
|
|
|
+import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys.DFS_DATA_TRANSFER_PROTECTION_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_HTTPS_KEYSTORE_RESOURCE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_SERVER_HTTPS_KEYSTORE_RESOURCE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_DELEGATION_TOKEN_ALWAYS_USE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_DATANODE_HTTP_ADDRESS_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_DATANODE_HTTPS_ADDRESS_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_DATANODE_KERBEROS_PRINCIPAL_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_DATANODE_KEYTAB_FILE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HTTP_POLICY_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL_KEY;
|
|
|
+import static org.apache.hadoop.hdfs.DFSConfigKeys.IGNORE_SECURE_PORTS_FOR_TESTING_KEY;
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
import static org.junit.Assert.assertFalse;
|
|
|
+import static org.junit.Assert.assertTrue;
|
|
|
import static org.mockito.Mockito.*;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
import java.net.HttpURLConnection;
|
|
|
-import java.net.InetSocketAddress;
|
|
|
import java.net.URI;
|
|
|
import java.net.URL;
|
|
|
import java.net.URLConnection;
|
|
|
import java.security.PrivilegedExceptionAction;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Properties;
|
|
|
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.FileSystem;
|
|
@@ -46,17 +63,18 @@ import org.apache.hadoop.hdfs.MiniDFSCluster;
|
|
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
|
|
import org.apache.hadoop.hdfs.web.resources.*;
|
|
|
import org.apache.hadoop.http.HttpConfig;
|
|
|
-import org.apache.hadoop.io.IOUtils;
|
|
|
import org.apache.hadoop.io.Text;
|
|
|
-import org.apache.hadoop.net.NetUtils;
|
|
|
+import org.apache.hadoop.minikdc.MiniKdc;
|
|
|
import org.apache.hadoop.security.SecurityUtil;
|
|
|
import org.apache.hadoop.security.UserGroupInformation;
|
|
|
import org.apache.hadoop.security.authentication.client.ConnectionConfigurator;
|
|
|
+import org.apache.hadoop.security.authentication.util.KerberosName;
|
|
|
import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
|
|
|
import org.apache.hadoop.security.token.SecretManager.InvalidToken;
|
|
|
import org.apache.hadoop.test.GenericTestUtils;
|
|
|
import org.apache.hadoop.test.Whitebox;
|
|
|
import org.apache.hadoop.security.token.Token;
|
|
|
+import org.junit.AfterClass;
|
|
|
import org.junit.Assert;
|
|
|
import org.junit.BeforeClass;
|
|
|
import org.junit.Test;
|
|
@@ -65,16 +83,95 @@ public class TestWebHdfsTokens {
|
|
|
private static Configuration conf;
|
|
|
URI uri = null;
|
|
|
|
|
|
+ //secure cluster
|
|
|
+ private static MiniKdc kdc = null;
|
|
|
+ private static File baseDir;
|
|
|
+ private static File keytabFile;
|
|
|
+ private static String username = "webhdfs-tokens-test";
|
|
|
+ private static String principal;
|
|
|
+ private static String keystoresDir;
|
|
|
+ private static String sslConfDir;
|
|
|
+
|
|
|
@BeforeClass
|
|
|
public static void setUp() {
|
|
|
conf = new Configuration();
|
|
|
+ }
|
|
|
+
|
|
|
+ @AfterClass
|
|
|
+ public static void destroy() throws Exception {
|
|
|
+ if (kdc != null) {
|
|
|
+ kdc.stop();
|
|
|
+ FileUtil.fullyDelete(baseDir);
|
|
|
+ KeyStoreTestUtil.cleanupSSLConfig(keystoresDir, sslConfDir);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void initEnv(){
|
|
|
SecurityUtil.setAuthenticationMethod(KERBEROS, conf);
|
|
|
- UserGroupInformation.setConfiguration(conf);
|
|
|
+ UserGroupInformation.setConfiguration(conf);
|
|
|
UserGroupInformation.setLoginUser(
|
|
|
UserGroupInformation.createUserForTesting(
|
|
|
"LoginUser", new String[]{"supergroup"}));
|
|
|
}
|
|
|
|
|
|
+ private static void initSecureConf(Configuration secureConf)
|
|
|
+ throws Exception {
|
|
|
+
|
|
|
+ baseDir = GenericTestUtils.getTestDir(
|
|
|
+ TestWebHdfsTokens.class.getSimpleName());
|
|
|
+ FileUtil.fullyDelete(baseDir);
|
|
|
+ assertTrue(baseDir.mkdirs());
|
|
|
+
|
|
|
+ Properties kdcConf = MiniKdc.createConf();
|
|
|
+ kdc = new MiniKdc(kdcConf, baseDir);
|
|
|
+ kdc.start();
|
|
|
+
|
|
|
+ SecurityUtil.setAuthenticationMethod(
|
|
|
+ UserGroupInformation.AuthenticationMethod.KERBEROS, secureConf);
|
|
|
+ UserGroupInformation.setConfiguration(secureConf);
|
|
|
+ KerberosName.resetDefaultRealm();
|
|
|
+ assertTrue("Expected secureConfiguration to enable security",
|
|
|
+ UserGroupInformation.isSecurityEnabled());
|
|
|
+
|
|
|
+ keytabFile = new File(baseDir, username + ".keytab");
|
|
|
+ String keytab = keytabFile.getAbsolutePath();
|
|
|
+ // Windows will not reverse name lookup "127.0.0.1" to "localhost".
|
|
|
+ String krbInstance = Path.WINDOWS ? "127.0.0.1" : "localhost";
|
|
|
+ principal = username + "/" + krbInstance + "@" + kdc.getRealm();
|
|
|
+ String spnegoPrincipal = "HTTP/" + krbInstance + "@" + kdc.getRealm();
|
|
|
+ kdc.createPrincipal(keytabFile, username, username + "/" + krbInstance,
|
|
|
+ "HTTP/" + krbInstance);
|
|
|
+
|
|
|
+ secureConf.set(DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, principal);
|
|
|
+ secureConf.set(DFS_NAMENODE_KEYTAB_FILE_KEY, keytab);
|
|
|
+ secureConf.set(DFS_DATANODE_KERBEROS_PRINCIPAL_KEY, principal);
|
|
|
+ secureConf.set(DFS_DATANODE_KEYTAB_FILE_KEY, keytab);
|
|
|
+ secureConf.set(DFS_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL_KEY,
|
|
|
+ spnegoPrincipal);
|
|
|
+ secureConf.setBoolean(DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY, true);
|
|
|
+ secureConf.set(DFS_DATA_TRANSFER_PROTECTION_KEY, "authentication");
|
|
|
+ secureConf.set(DFS_HTTP_POLICY_KEY,
|
|
|
+ HttpConfig.Policy.HTTP_AND_HTTPS.name());
|
|
|
+ secureConf.set(DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0");
|
|
|
+ secureConf.set(DFS_NAMENODE_HTTP_ADDRESS_KEY, "localhost:0");
|
|
|
+ secureConf.set(DFS_DATANODE_HTTPS_ADDRESS_KEY, "localhost:0");
|
|
|
+ secureConf.set(DFS_DATANODE_HTTP_ADDRESS_KEY, "localhost:0");
|
|
|
+ secureConf.setBoolean(DFS_NAMENODE_DELEGATION_TOKEN_ALWAYS_USE_KEY, true);
|
|
|
+ secureConf.setBoolean(IGNORE_SECURE_PORTS_FOR_TESTING_KEY, true);
|
|
|
+
|
|
|
+ keystoresDir = baseDir.getAbsolutePath();
|
|
|
+ sslConfDir = KeyStoreTestUtil.getClasspathDir(TestWebHdfsTokens.class);
|
|
|
+ KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir,
|
|
|
+ secureConf, false);
|
|
|
+
|
|
|
+ secureConf.set(DFS_CLIENT_HTTPS_KEYSTORE_RESOURCE_KEY,
|
|
|
+ KeyStoreTestUtil.getClientSSLConfigFileName());
|
|
|
+ secureConf.set(DFS_SERVER_HTTPS_KEYSTORE_RESOURCE_KEY,
|
|
|
+ KeyStoreTestUtil.getServerSSLConfigFileName());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
private WebHdfsFileSystem spyWebhdfsInSecureSetup() throws IOException {
|
|
|
WebHdfsFileSystem fsOrig = new WebHdfsFileSystem();
|
|
|
fsOrig.initialize(URI.create("webhdfs://127.0.0.1:0"), conf);
|
|
@@ -84,6 +181,7 @@ public class TestWebHdfsTokens {
|
|
|
|
|
|
@Test(timeout = 5000)
|
|
|
public void testTokenForNonTokenOp() throws IOException {
|
|
|
+ initEnv();
|
|
|
WebHdfsFileSystem fs = spyWebhdfsInSecureSetup();
|
|
|
Token<?> token = mock(Token.class);
|
|
|
doReturn(token).when(fs).getDelegationToken(null);
|
|
@@ -104,16 +202,19 @@ public class TestWebHdfsTokens {
|
|
|
|
|
|
@Test(timeout = 5000)
|
|
|
public void testNoTokenForGetToken() throws IOException {
|
|
|
+ initEnv();
|
|
|
checkNoTokenForOperation(GetOpParam.Op.GETDELEGATIONTOKEN);
|
|
|
}
|
|
|
|
|
|
@Test(timeout = 5000)
|
|
|
public void testNoTokenForRenewToken() throws IOException {
|
|
|
+ initEnv();
|
|
|
checkNoTokenForOperation(PutOpParam.Op.RENEWDELEGATIONTOKEN);
|
|
|
}
|
|
|
|
|
|
@Test(timeout = 5000)
|
|
|
public void testNoTokenForCancelToken() throws IOException {
|
|
|
+ initEnv();
|
|
|
checkNoTokenForOperation(PutOpParam.Op.CANCELDELEGATIONTOKEN);
|
|
|
}
|
|
|
|
|
@@ -162,86 +263,42 @@ public class TestWebHdfsTokens {
|
|
|
@Test
|
|
|
public void testLazyTokenFetchForWebhdfs() throws Exception {
|
|
|
MiniDFSCluster cluster = null;
|
|
|
- WebHdfsFileSystem fs = null;
|
|
|
+ UserGroupInformation ugi = null;
|
|
|
try {
|
|
|
final Configuration clusterConf = new HdfsConfiguration(conf);
|
|
|
- SecurityUtil.setAuthenticationMethod(SIMPLE, clusterConf);
|
|
|
- clusterConf.setBoolean(DFSConfigKeys
|
|
|
- .DFS_NAMENODE_DELEGATION_TOKEN_ALWAYS_USE_KEY, true);
|
|
|
+ initSecureConf(clusterConf);
|
|
|
|
|
|
- // trick the NN into thinking security is enabled w/o it trying
|
|
|
- // to login from a keytab
|
|
|
- UserGroupInformation.setConfiguration(clusterConf);
|
|
|
cluster = new MiniDFSCluster.Builder(clusterConf).numDataNodes(1).build();
|
|
|
cluster.waitActive();
|
|
|
- SecurityUtil.setAuthenticationMethod(KERBEROS, clusterConf);
|
|
|
- UserGroupInformation.setConfiguration(clusterConf);
|
|
|
-
|
|
|
+
|
|
|
+ ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(
|
|
|
+ principal, keytabFile.getAbsolutePath());
|
|
|
+
|
|
|
+ //test with swebhdfs
|
|
|
+ uri = DFSUtil.createUri(
|
|
|
+ "swebhdfs", cluster.getNameNode().getHttpsAddress());
|
|
|
+ validateLazyTokenFetch(ugi, clusterConf);
|
|
|
+
|
|
|
+ //test with webhdfs
|
|
|
uri = DFSUtil.createUri(
|
|
|
"webhdfs", cluster.getNameNode().getHttpAddress());
|
|
|
- validateLazyTokenFetch(clusterConf);
|
|
|
+ validateLazyTokenFetch(ugi, clusterConf);
|
|
|
+
|
|
|
} finally {
|
|
|
- IOUtils.cleanup(null, fs);
|
|
|
if (cluster != null) {
|
|
|
cluster.shutdown();
|
|
|
}
|
|
|
+
|
|
|
+ // Reset UGI so that other tests are not affected.
|
|
|
+ UserGroupInformation.reset();
|
|
|
+ UserGroupInformation.setConfiguration(new Configuration());
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- @Test
|
|
|
- public void testLazyTokenFetchForSWebhdfs() throws Exception {
|
|
|
- MiniDFSCluster cluster = null;
|
|
|
- SWebHdfsFileSystem fs = null;
|
|
|
- String keystoresDir;
|
|
|
- String sslConfDir;
|
|
|
- try {
|
|
|
- final Configuration clusterConf = new HdfsConfiguration(conf);
|
|
|
- SecurityUtil.setAuthenticationMethod(SIMPLE, clusterConf);
|
|
|
- clusterConf.setBoolean(DFSConfigKeys
|
|
|
- .DFS_NAMENODE_DELEGATION_TOKEN_ALWAYS_USE_KEY, true);
|
|
|
- String baseDir =
|
|
|
- GenericTestUtils.getTempPath(TestWebHdfsTokens.class.getSimpleName());
|
|
|
-
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_HTTP_POLICY_KEY, HttpConfig.Policy.HTTPS_ONLY.name());
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0");
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_DATANODE_HTTPS_ADDRESS_KEY, "localhost:0");
|
|
|
-
|
|
|
- File base = new File(baseDir);
|
|
|
- FileUtil.fullyDelete(base);
|
|
|
- base.mkdirs();
|
|
|
- keystoresDir = new File(baseDir).getAbsolutePath();
|
|
|
- sslConfDir = KeyStoreTestUtil.getClasspathDir(TestWebHdfsTokens.class);
|
|
|
- KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir, clusterConf, false);
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_CLIENT_HTTPS_KEYSTORE_RESOURCE_KEY,
|
|
|
- KeyStoreTestUtil.getClientSSLConfigFileName());
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_SERVER_HTTPS_KEYSTORE_RESOURCE_KEY,
|
|
|
- KeyStoreTestUtil.getServerSSLConfigFileName());
|
|
|
-
|
|
|
- // trick the NN into thinking security is enabled w/o it trying
|
|
|
- // to login from a keytab
|
|
|
- UserGroupInformation.setConfiguration(clusterConf);
|
|
|
- cluster = new MiniDFSCluster.Builder(clusterConf).numDataNodes(1).build();
|
|
|
- cluster.waitActive();
|
|
|
- InetSocketAddress addr = cluster.getNameNode().getHttpsAddress();
|
|
|
- String nnAddr = NetUtils.getHostPortString(addr);
|
|
|
- clusterConf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, nnAddr);
|
|
|
- SecurityUtil.setAuthenticationMethod(KERBEROS, clusterConf);
|
|
|
- UserGroupInformation.setConfiguration(clusterConf);
|
|
|
-
|
|
|
- uri = DFSUtil.createUri(
|
|
|
- "swebhdfs", cluster.getNameNode().getHttpsAddress());
|
|
|
- validateLazyTokenFetch(clusterConf);
|
|
|
- } finally {
|
|
|
- IOUtils.cleanup(null, fs);
|
|
|
- if (cluster != null) {
|
|
|
- cluster.shutdown();
|
|
|
- }
|
|
|
- }
|
|
|
- KeyStoreTestUtil.cleanupSSLConfig(keystoresDir, sslConfDir);
|
|
|
- }
|
|
|
+
|
|
|
|
|
|
@Test
|
|
|
public void testSetTokenServiceAndKind() throws Exception {
|
|
|
+ initEnv();
|
|
|
MiniDFSCluster cluster = null;
|
|
|
|
|
|
try {
|
|
@@ -296,16 +353,20 @@ public class TestWebHdfsTokens {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void validateLazyTokenFetch(final Configuration clusterConf) throws Exception{
|
|
|
- final String testUser = "DummyUser";
|
|
|
- UserGroupInformation ugi = UserGroupInformation.createUserForTesting(
|
|
|
- testUser, new String[]{"supergroup"});
|
|
|
- WebHdfsFileSystem fs = ugi.doAs(new PrivilegedExceptionAction<WebHdfsFileSystem>() {
|
|
|
- @Override
|
|
|
- public WebHdfsFileSystem run() throws IOException {
|
|
|
- return spy((WebHdfsFileSystem) FileSystem.newInstance(uri, clusterConf));
|
|
|
- }
|
|
|
- });
|
|
|
+ private void validateLazyTokenFetch(UserGroupInformation ugi,
|
|
|
+ final Configuration clusterConf) throws Exception {
|
|
|
+
|
|
|
+ String testUser = ugi.getShortUserName();
|
|
|
+
|
|
|
+ WebHdfsFileSystem fs = ugi.doAs(
|
|
|
+ new PrivilegedExceptionAction<WebHdfsFileSystem>() {
|
|
|
+ @Override
|
|
|
+ public WebHdfsFileSystem run() throws IOException {
|
|
|
+ return spy((WebHdfsFileSystem) FileSystem.newInstance(uri,
|
|
|
+ clusterConf));
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
// verify token ops don't get a token
|
|
|
Assert.assertNull(fs.getRenewToken());
|
|
|
Token<?> token = fs.getDelegationToken(null);
|