|
@@ -22,15 +22,23 @@ import static org.apache.hadoop.mapreduce.v2.app.webapp.AMParams.APP_ID;
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.File;
|
|
|
import java.io.InputStream;
|
|
|
import java.net.HttpURLConnection;
|
|
|
+import java.net.SocketException;
|
|
|
import java.net.URL;
|
|
|
+import java.security.KeyPair;
|
|
|
+import java.security.cert.Certificate;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
import java.util.Map.Entry;
|
|
|
|
|
|
+import javax.net.ssl.HttpsURLConnection;
|
|
|
import javax.net.ssl.SSLException;
|
|
|
|
|
|
+import org.apache.hadoop.mapreduce.MRJobConfig;
|
|
|
+import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
|
|
|
import org.junit.Assert;
|
|
|
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
@@ -57,13 +65,26 @@ import org.apache.hadoop.yarn.webapp.WebApps;
|
|
|
import org.apache.hadoop.yarn.webapp.test.WebAppTests;
|
|
|
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
|
|
|
import org.apache.http.HttpStatus;
|
|
|
+import org.junit.After;
|
|
|
+import org.junit.Rule;
|
|
|
import org.junit.Test;
|
|
|
|
|
|
import com.google.common.net.HttpHeaders;
|
|
|
import com.google.inject.Injector;
|
|
|
+import org.junit.contrib.java.lang.system.EnvironmentVariables;
|
|
|
|
|
|
public class TestAMWebApp {
|
|
|
|
|
|
+ private static final File TEST_DIR = new File(
|
|
|
+ System.getProperty("test.build.data",
|
|
|
+ System.getProperty("java.io.tmpdir")),
|
|
|
+ TestAMWebApp.class.getName());
|
|
|
+
|
|
|
+ @After
|
|
|
+ public void tearDown() {
|
|
|
+ TEST_DIR.delete();
|
|
|
+ }
|
|
|
+
|
|
|
@Test public void testAppControllerIndex() {
|
|
|
AppContext ctx = new MockAppContext(0, 1, 1, 1);
|
|
|
Injector injector = WebAppTests.createMockInjector(AppContext.class, ctx);
|
|
@@ -179,7 +200,7 @@ public class TestAMWebApp {
|
|
|
}
|
|
|
};
|
|
|
Configuration conf = new Configuration();
|
|
|
- // MR is explicitly disabling SSL, even though setting as HTTPS_ONLY
|
|
|
+ // MR is explicitly disabling SSL, even though YARN setting as HTTPS_ONLY
|
|
|
conf.set(YarnConfiguration.YARN_HTTP_POLICY_KEY, Policy.HTTPS_ONLY.name());
|
|
|
Job job = app.submit(conf);
|
|
|
|
|
@@ -201,12 +222,143 @@ public class TestAMWebApp {
|
|
|
(HttpURLConnection) httpsUrl.openConnection();
|
|
|
httpsConn.getInputStream();
|
|
|
Assert.fail("https:// is not accessible, expected to fail");
|
|
|
- } catch (Exception e) {
|
|
|
- Assert.assertTrue(e instanceof SSLException);
|
|
|
+ } catch (SSLException e) {
|
|
|
+ // expected
|
|
|
+ }
|
|
|
+
|
|
|
+ app.waitForState(job, JobState.SUCCEEDED);
|
|
|
+ app.verifyCompleted();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Rule
|
|
|
+ public final EnvironmentVariables environmentVariables
|
|
|
+ = new EnvironmentVariables();
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testMRWebAppSSLEnabled() throws Exception {
|
|
|
+ MRApp app = new MRApp(2, 2, true, this.getClass().getName(), true) {
|
|
|
+ @Override
|
|
|
+ protected ClientService createClientService(AppContext context) {
|
|
|
+ return new MRClientService(context);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ Configuration conf = new Configuration();
|
|
|
+ conf.setBoolean(MRJobConfig.MR_AM_WEBAPP_HTTPS_ENABLED, true);
|
|
|
+
|
|
|
+ KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA");
|
|
|
+ Certificate cert = KeyStoreTestUtil.generateCertificate(
|
|
|
+ "CN=foo", keyPair, 5, "SHA512WITHRSA");
|
|
|
+ File keystoreFile = new File(TEST_DIR, "server.keystore");
|
|
|
+ keystoreFile.getParentFile().mkdirs();
|
|
|
+ KeyStoreTestUtil.createKeyStore(keystoreFile.getAbsolutePath(), "password",
|
|
|
+ "server", keyPair.getPrivate(), cert);
|
|
|
+ environmentVariables.set("KEYSTORE_FILE_LOCATION",
|
|
|
+ keystoreFile.getAbsolutePath());
|
|
|
+ environmentVariables.set("KEYSTORE_PASSWORD", "password");
|
|
|
+
|
|
|
+ Job job = app.submit(conf);
|
|
|
+
|
|
|
+ String hostPort =
|
|
|
+ NetUtils.getHostPortString(((MRClientService) app.getClientService())
|
|
|
+ .getWebApp().getListenerAddress());
|
|
|
+ // https:// should be accessible
|
|
|
+ URL httpsUrl = new URL("https://" + hostPort);
|
|
|
+ HttpsURLConnection httpsConn =
|
|
|
+ (HttpsURLConnection) httpsUrl.openConnection();
|
|
|
+ KeyStoreTestUtil.setAllowAllSSL(httpsConn);
|
|
|
+
|
|
|
+ InputStream in = httpsConn.getInputStream();
|
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
+ IOUtils.copyBytes(in, out, 1024);
|
|
|
+ Assert.assertTrue(out.toString().contains("MapReduce Application"));
|
|
|
+
|
|
|
+ // http:// is not accessible.
|
|
|
+ URL httpUrl = new URL("http://" + hostPort);
|
|
|
+ try {
|
|
|
+ HttpURLConnection httpConn =
|
|
|
+ (HttpURLConnection) httpUrl.openConnection();
|
|
|
+ httpConn.getResponseCode();
|
|
|
+ Assert.fail("http:// is not accessible, expected to fail");
|
|
|
+ } catch (SocketException e) {
|
|
|
+ // expected
|
|
|
}
|
|
|
|
|
|
app.waitForState(job, JobState.SUCCEEDED);
|
|
|
app.verifyCompleted();
|
|
|
+
|
|
|
+ keystoreFile.delete();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testMRWebAppSSLEnabledWithClientAuth() throws Exception {
|
|
|
+ MRApp app = new MRApp(2, 2, true, this.getClass().getName(), true) {
|
|
|
+ @Override
|
|
|
+ protected ClientService createClientService(AppContext context) {
|
|
|
+ return new MRClientService(context);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ Configuration conf = new Configuration();
|
|
|
+ conf.setBoolean(MRJobConfig.MR_AM_WEBAPP_HTTPS_ENABLED, true);
|
|
|
+ conf.setBoolean(MRJobConfig.MR_AM_WEBAPP_HTTPS_CLIENT_AUTH, true);
|
|
|
+
|
|
|
+ KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA");
|
|
|
+ Certificate cert = KeyStoreTestUtil.generateCertificate(
|
|
|
+ "CN=foo", keyPair, 5, "SHA512WITHRSA");
|
|
|
+ File keystoreFile = new File(TEST_DIR, "server.keystore");
|
|
|
+ keystoreFile.getParentFile().mkdirs();
|
|
|
+ KeyStoreTestUtil.createKeyStore(keystoreFile.getAbsolutePath(), "password",
|
|
|
+ "server", keyPair.getPrivate(), cert);
|
|
|
+ environmentVariables.set("KEYSTORE_FILE_LOCATION",
|
|
|
+ keystoreFile.getAbsolutePath());
|
|
|
+ environmentVariables.set("KEYSTORE_PASSWORD", "password");
|
|
|
+
|
|
|
+ KeyPair clientKeyPair = KeyStoreTestUtil.generateKeyPair("RSA");
|
|
|
+ X509Certificate clientCert = KeyStoreTestUtil.generateCertificate(
|
|
|
+ "CN=bar", clientKeyPair, 5, "SHA512WITHRSA");
|
|
|
+ File truststoreFile = new File(TEST_DIR, "client.truststore");
|
|
|
+ truststoreFile.getParentFile().mkdirs();
|
|
|
+ KeyStoreTestUtil.createTrustStore(truststoreFile.getAbsolutePath(),
|
|
|
+ "password", "client", clientCert);
|
|
|
+ environmentVariables.set("TRUSTSTORE_FILE_LOCATION",
|
|
|
+ truststoreFile.getAbsolutePath());
|
|
|
+ environmentVariables.set("TRUSTSTORE_PASSWORD", "password");
|
|
|
+
|
|
|
+ Job job = app.submit(conf);
|
|
|
+
|
|
|
+ String hostPort =
|
|
|
+ NetUtils.getHostPortString(((MRClientService) app.getClientService())
|
|
|
+ .getWebApp().getListenerAddress());
|
|
|
+ // https:// should be accessible
|
|
|
+ URL httpsUrl = new URL("https://" + hostPort);
|
|
|
+ HttpsURLConnection httpsConn =
|
|
|
+ (HttpsURLConnection) httpsUrl.openConnection();
|
|
|
+ KeyStoreTestUtil.setAllowAllSSL(httpsConn, clientCert, clientKeyPair);
|
|
|
+
|
|
|
+ InputStream in = httpsConn.getInputStream();
|
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
+ IOUtils.copyBytes(in, out, 1024);
|
|
|
+ Assert.assertTrue(out.toString().contains("MapReduce Application"));
|
|
|
+
|
|
|
+ // Try with wrong client cert
|
|
|
+ KeyPair otherClientKeyPair = KeyStoreTestUtil.generateKeyPair("RSA");
|
|
|
+ X509Certificate otherClientCert = KeyStoreTestUtil.generateCertificate(
|
|
|
+ "CN=bar", otherClientKeyPair, 5, "SHA512WITHRSA");
|
|
|
+ KeyStoreTestUtil.setAllowAllSSL(httpsConn, otherClientCert, clientKeyPair);
|
|
|
+
|
|
|
+ try {
|
|
|
+ HttpURLConnection httpConn =
|
|
|
+ (HttpURLConnection) httpsUrl.openConnection();
|
|
|
+ httpConn.getResponseCode();
|
|
|
+ Assert.fail("Wrong client certificate, expected to fail");
|
|
|
+ } catch (SSLException e) {
|
|
|
+ // expected
|
|
|
+ }
|
|
|
+
|
|
|
+ app.waitForState(job, JobState.SUCCEEDED);
|
|
|
+ app.verifyCompleted();
|
|
|
+
|
|
|
+ keystoreFile.delete();
|
|
|
+ truststoreFile.delete();
|
|
|
}
|
|
|
|
|
|
static String webProxyBase = null;
|