http://git-wip-us.apache.org/repos/asf/hadoop/blob/c2288ac4/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/ProxyCA.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/ProxyCA.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/ProxyCA.java
new file mode 100644
index 0000000..26760d3
--- /dev/null
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/ProxyCA.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.yarn.server.webproxy;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.util.PublicSuffixMatcherLoader;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.bouncycastle.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * Allows for the generation and acceptance of specialized HTTPS Certificates 
to
+ * be used for HTTPS communication between the AMs and the RM Proxy.
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class ProxyCA {
+  private static final Logger LOG = LoggerFactory.getLogger(ProxyCA.class);
+
+  private X509Certificate caCert;
+  private KeyPair caKeyPair;
+  private KeyStore childTrustStore;
+  private final Random srand;
+  private X509TrustManager defaultTrustManager;
+  private X509KeyManager x509KeyManager;
+  private HostnameVerifier hostnameVerifier;
+  private static final AlgorithmIdentifier SIG_ALG_ID =
+      new DefaultSignatureAlgorithmIdentifierFinder().find("SHA512WITHRSA");
+
+  public ProxyCA() {
+    srand = new SecureRandom();
+
+    // This only has to be done once
+    Security.addProvider(new BouncyCastleProvider());
+  }
+
+  public void init() throws GeneralSecurityException, IOException {
+    createCACertAndKeyPair();
+
+    defaultTrustManager = null;
+    TrustManagerFactory factory = TrustManagerFactory.getInstance(
+        TrustManagerFactory.getDefaultAlgorithm());
+    factory.init((KeyStore) null);
+    for (TrustManager manager : factory.getTrustManagers()) {
+      if (manager instanceof X509TrustManager) {
+        defaultTrustManager = (X509TrustManager) manager;
+        break;
+      }
+    }
+    if (defaultTrustManager == null) {
+      throw new YarnRuntimeException(
+          "Could not find default X509 Trust Manager");
+    }
+
+    this.x509KeyManager = createKeyManager();
+    this.hostnameVerifier = createHostnameVerifier();
+    this.childTrustStore = createTrustStore("client", caCert);
+  }
+
+  private X509Certificate createCert(boolean isCa, String issuerStr,
+      String subjectStr, Date from, Date to, PublicKey publicKey,
+      PrivateKey privateKey) throws GeneralSecurityException, IOException {
+    X500Name issuer = new X500Name(issuerStr);
+    X500Name subject = new X500Name(subjectStr);
+    SubjectPublicKeyInfo subPubKeyInfo =
+        SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
+    X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
+        issuer, new BigInteger(64, srand), from, to, subject, subPubKeyInfo);
+    AlgorithmIdentifier digAlgId =
+        new DefaultDigestAlgorithmIdentifierFinder().find(SIG_ALG_ID);
+    ContentSigner contentSigner;
+    try {
+      contentSigner = new BcRSAContentSignerBuilder(SIG_ALG_ID, digAlgId)
+          .build(PrivateKeyFactory.createKey(privateKey.getEncoded()));
+    } catch (OperatorCreationException oce) {
+      throw new GeneralSecurityException(oce);
+    }
+    if (isCa) {
+      // BasicConstraints(0) indicates a CA and a path length of 0.  This is
+      // important to indicate that child certificates can't issue additional
+      // grandchild certificates
+      certBuilder.addExtension(Extension.basicConstraints, true,
+          new BasicConstraints(0));
+    } else {
+      // BasicConstraints(false) indicates this is not a CA
+      certBuilder.addExtension(Extension.basicConstraints, true,
+          new BasicConstraints(false));
+      certBuilder.addExtension(Extension.authorityKeyIdentifier, false,
+          new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caCert));
+    }
+    X509CertificateHolder certHolder = certBuilder.build(contentSigner);
+    X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC")
+        .getCertificate(certHolder);
+    LOG.info("Created Certificate for {}", subject);
+    return cert;
+  }
+
+  private void createCACertAndKeyPair()
+      throws GeneralSecurityException, IOException {
+    Date from = new Date();
+    Date to = new GregorianCalendar(2037, Calendar.DECEMBER, 31).getTime();
+    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+    keyGen.initialize(2048);
+    caKeyPair = keyGen.genKeyPair();
+    String subject = "OU=YARN-" + UUID.randomUUID();
+    caCert = createCert(true, subject, subject, from, to,
+        caKeyPair.getPublic(), caKeyPair.getPrivate());
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("CA Certificate: \n{}", caCert);
+    }
+  }
+
+  public byte[] createChildKeyStore(ApplicationId appId, String ksPassword)
+      throws Exception {
+    // We don't check the expiration date, and this will provide further reason
+    // for outside users to not accept these certificates
+    Date from = new Date();
+    Date to = from;
+    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+    keyGen.initialize(2048);
+    KeyPair keyPair = keyGen.genKeyPair();
+    String issuer = caCert.getSubjectX500Principal().getName();
+    String subject = "CN=" + appId;
+    X509Certificate cert = createCert(false, issuer, subject, from, to,
+        keyPair.getPublic(), caKeyPair.getPrivate());
+    if (LOG.isTraceEnabled()) {
+      LOG.trace("Certificate for {}: \n{}", appId, cert);
+    }
+
+    KeyStore keyStore = createChildKeyStore(ksPassword, "server",
+        keyPair.getPrivate(), cert);
+    return keyStoreToBytes(keyStore, ksPassword);
+  }
+
+  public byte[] getChildTrustStore(String password)
+      throws GeneralSecurityException, IOException {
+    return keyStoreToBytes(childTrustStore, password);
+  }
+
+  private KeyStore createEmptyKeyStore()
+      throws GeneralSecurityException, IOException {
+    KeyStore ks = KeyStore.getInstance("JKS");
+    ks.load(null, null); // initialize
+    return ks;
+  }
+
+  private KeyStore createChildKeyStore(String password, String alias,
+      Key privateKey, Certificate cert)
+      throws GeneralSecurityException, IOException {
+    KeyStore ks = createEmptyKeyStore();
+    ks.setKeyEntry(alias, privateKey, password.toCharArray(),
+        new Certificate[]{cert, caCert});
+    return ks;
+  }
+
+  public String generateKeyStorePassword() {
+    return RandomStringUtils.random(16, 0, 0, true, true, null, srand);
+  }
+
+  private byte[] keyStoreToBytes(KeyStore ks, String password)
+      throws GeneralSecurityException, IOException {
+    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+      ks.store(out, password.toCharArray());
+      return out.toByteArray();
+    }
+  }
+
+  private KeyStore createTrustStore(String alias, Certificate cert)
+      throws GeneralSecurityException, IOException {
+    KeyStore ks = createEmptyKeyStore();
+    ks.setCertificateEntry(alias, cert);
+    return ks;
+  }
+
+  public SSLContext createSSLContext(ApplicationId appId)
+      throws GeneralSecurityException {
+    // We need the normal TrustManager, plus our custom one.  While the
+    // SSLContext accepts an array of TrustManagers, the docs indicate that 
only
+    // the first instance of any particular implementation type is used
+    // (e.g. X509KeyManager) - this means that simply putting both 
TrustManagers
+    // in won't work.  We need to have ours do both.
+    TrustManager[] trustManagers = new TrustManager[] {
+        createTrustManager(appId)};
+    KeyManager[] keyManagers = new KeyManager[]{x509KeyManager};
+
+    SSLContext sc = SSLContext.getInstance("SSL");
+    sc.init(keyManagers, trustManagers, new SecureRandom());
+    return sc;
+  }
+
+  @VisibleForTesting
+  X509TrustManager createTrustManager(ApplicationId appId) {
+    return new X509TrustManager() {
+      @Override
+      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+        return defaultTrustManager.getAcceptedIssuers();
+      }
+
+      @Override
+      public void checkClientTrusted(
+          java.security.cert.X509Certificate[] certs, String authType) {
+        // not used
+      }
+
+      @Override
+      public void checkServerTrusted(
+          java.security.cert.X509Certificate[] certs, String authType)
+          throws CertificateException {
+        // Our certs will always have 2 in the chain, with 0 being the app's
+        // cert and 1 being the RM's cert
+        boolean issuedByRM = false;
+        if (certs.length == 2) {
+          try {
+            // We can verify both certs using the CA cert's public key - the
+            // child cert's info is not needed
+            certs[0].verify(caKeyPair.getPublic());
+            certs[1].verify(caKeyPair.getPublic());
+            issuedByRM = true;
+          } catch (CertificateException | NoSuchAlgorithmException
+              | InvalidKeyException | NoSuchProviderException
+              | SignatureException e) {
+            // Fall back to the default trust manager
+            LOG.debug("Could not verify certificate with RM CA, falling " +
+                "back to default", e);
+            defaultTrustManager.checkServerTrusted(certs, authType);
+          }
+        } else {
+          LOG.debug("Certificate not issued by RM CA, falling back to " +
+              "default");
+          defaultTrustManager.checkServerTrusted(certs, authType);
+        }
+        if (issuedByRM) {
+          // Check that it has the correct App ID
+          if (!certs[0].getSubjectX500Principal().getName()
+              .equals("CN=" + appId)) {
+            throw new CertificateException(
+                "Expected to find Subject X500 Principal with CN="
+                    + appId + " but found "
+                    + certs[0].getSubjectX500Principal().getName());
+          }
+          LOG.debug("Verified certificate signed by RM CA");
+        }
+      }
+    };
+  }
+
+  @VisibleForTesting
+  X509KeyManager getX509KeyManager() {
+    return x509KeyManager;
+  }
+
+  private X509KeyManager createKeyManager() {
+    return new X509KeyManager() {
+      @Override
+      public String[] getClientAliases(String s, Principal[] principals) {
+        return new String[]{"client"};
+      }
+
+      @Override
+      public String chooseClientAlias(String[] strings,
+          Principal[] principals, Socket socket) {
+        return "client";
+      }
+
+      @Override
+      public String[] getServerAliases(String s, Principal[] principals) {
+        return null;
+      }
+
+      @Override
+      public String chooseServerAlias(String s, Principal[] principals,
+          Socket socket) {
+        return null;
+      }
+
+      @Override
+      public X509Certificate[] getCertificateChain(String s) {
+        return new X509Certificate[]{caCert};
+      }
+
+      @Override
+      public PrivateKey getPrivateKey(String s) {
+        return caKeyPair.getPrivate();
+      }
+    };
+  }
+
+  public HostnameVerifier getHostnameVerifier() {
+    return hostnameVerifier;
+  }
+
+  private HostnameVerifier createHostnameVerifier() {
+    HostnameVerifier defaultHostnameVerifier =
+        new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
+    return new HostnameVerifier() {
+      @Override
+      public boolean verify(String host, SSLSession sslSession) {
+        try {
+          Certificate[] certs = sslSession.getPeerCertificates();
+          if (certs.length == 2) {
+            // Make sure this is one of our certs.  More thorough checking 
would
+            // have already been done by the SSLContext
+            certs[0].verify(caKeyPair.getPublic());
+            LOG.debug("Verified certificate signed by RM CA, " +
+                "skipping hostname verification");
+            return true;
+          }
+        } catch (SSLPeerUnverifiedException e) {
+          // No certificate
+          return false;
+        } catch (CertificateException | NoSuchAlgorithmException
+            | InvalidKeyException | SignatureException
+            | NoSuchProviderException e) {
+          // fall back to normal verifier below
+          LOG.debug("Could not verify certificate with RM CA, " +
+              "falling back to default hostname verification", e);
+        }
+        return defaultHostnameVerifier.verify(host, sslSession);
+      }
+    };
+  }
+
+  @VisibleForTesting
+  void setDefaultTrustManager(X509TrustManager trustManager) {
+    this.defaultTrustManager = trustManager;
+  }
+
+  @VisibleForTesting
+  public X509Certificate getCaCert() {
+    return caCert;
+  }
+
+  @VisibleForTesting
+  public KeyPair getCaKeyPair() {
+    return caKeyPair;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/c2288ac4/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxy.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxy.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxy.java
index 71679cc..f205cf7 100644
--- 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxy.java
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxy.java
@@ -39,6 +39,7 @@ public class WebAppProxy extends AbstractService {
   public static final String FETCHER_ATTRIBUTE= "AppUrlFetcher";
   public static final String IS_SECURITY_ENABLED_ATTRIBUTE = 
"IsSecurityEnabled";
   public static final String PROXY_HOST_ATTRIBUTE = "proxyHost";
+  public static final String PROXY_CA = "ProxyCA";
   private static final Logger LOG = LoggerFactory.getLogger(
       WebAppProxy.class);
   

http://git-wip-us.apache.org/repos/asf/hadoop/blob/c2288ac4/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxyServlet.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxyServlet.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxyServlet.java
index f21ff2c..2dc3a46 100644
--- 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxyServlet.java
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/main/java/org/apache/hadoop/yarn/server/webproxy/WebAppProxyServlet.java
@@ -45,6 +45,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriBuilderException;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.net.NetUtils;
 import org.apache.hadoop.yarn.api.records.ApplicationId;
@@ -63,15 +64,14 @@ import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
 import org.apache.http.Header;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.params.ClientPNames;
-import org.apache.http.client.params.CookiePolicy;
 import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.conn.params.ConnRoutePNames;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -177,6 +177,39 @@ public class WebAppProxyServlet extends HttpServlet {
         __().
         __();
   }
+
+  /**
+   * Show the user a page that says that HTTPS must be used but was not.
+   * @param resp the http response
+   * @param link the link to point to
+   * @return true if HTTPS must be used but was not, false otherwise
+   * @throws IOException on any error.
+   */
+  @VisibleForTesting
+  static boolean checkHttpsStrictAndNotProvided(
+      HttpServletResponse resp, URI link, YarnConfiguration conf)
+      throws IOException {
+    String httpsPolicy = conf.get(
+        YarnConfiguration.RM_APPLICATION_HTTPS_POLICY,
+        YarnConfiguration.DEFAULT_RM_APPLICATION_HTTPS_POLICY);
+    boolean required = httpsPolicy.equals("STRICT");
+    boolean provided = link.getScheme().equals("https");
+    if (required && !provided) {
+      resp.setContentType(MimeType.HTML);
+      Page p = new Page(resp.getWriter());
+      p.html().
+          h1("HTTPS must be used").
+          h3().
+          __(YarnConfiguration.RM_APPLICATION_HTTPS_POLICY,
+              "is set to STRICT, which means that the tracking URL ",
+              "must be an HTTPS URL, but it is not.").
+          __("The tracking URL is: ", link).
+          __().
+          __();
+      return true;
+    }
+    return false;
+  }
   
   /**
    * Download link and have it be the response.
@@ -186,17 +219,31 @@ public class WebAppProxyServlet extends HttpServlet {
    * @param c the cookie to set if any
    * @param proxyHost the proxy host
    * @param method the http method
+   * @param appId the ApplicationID
    * @throws IOException on any error.
    */
-  private static void proxyLink(final HttpServletRequest req,
+  private void proxyLink(final HttpServletRequest req,
       final HttpServletResponse resp, final URI link, final Cookie c,
-      final String proxyHost, final HTTP method) throws IOException {
-    DefaultHttpClient client = new DefaultHttpClient();
-    client
-        .getParams()
-        .setParameter(ClientPNames.COOKIE_POLICY,
-            CookiePolicy.BROWSER_COMPATIBILITY)
-        .setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
+      final String proxyHost, final HTTP method, final ApplicationId appId)
+      throws IOException {
+    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
+
+    String httpsPolicy = 
conf.get(YarnConfiguration.RM_APPLICATION_HTTPS_POLICY,
+        YarnConfiguration.DEFAULT_RM_APPLICATION_HTTPS_POLICY);
+    if (httpsPolicy.equals("LENIENT") || httpsPolicy.equals("STRICT")) {
+      ProxyCA proxyCA = getProxyCA();
+      // ProxyCA could be null when the Proxy is run outside the RM
+      if (proxyCA != null) {
+        try {
+          httpClientBuilder.setSSLContext(proxyCA.createSSLContext(appId));
+          httpClientBuilder.setSSLHostnameVerifier(
+              proxyCA.getHostnameVerifier());
+        } catch (Exception e) {
+          throw new IOException(e);
+        }
+      }
+    }
+
     // Make sure we send the request from the proxy address in the config
     // since that is what the AM filter checks against. IP aliasing or
     // similar could cause issues otherwise.
@@ -204,8 +251,11 @@ public class WebAppProxyServlet extends HttpServlet {
     if (LOG.isDebugEnabled()) {
       LOG.debug("local InetAddress for proxy host: {}", localAddress);
     }
-    client.getParams()
-        .setParameter(ConnRoutePNames.LOCAL_ADDRESS, localAddress);
+    httpClientBuilder.setDefaultRequestConfig(
+        RequestConfig.custom()
+        .setCircularRedirectsAllowed(true)
+        .setLocalAddress(localAddress)
+        .build());
 
     HttpRequestBase base = null;
     if (method.equals(HTTP.GET)) {
@@ -247,6 +297,7 @@ public class WebAppProxyServlet extends HttpServlet {
           PROXY_USER_COOKIE_NAME + "=" + URLEncoder.encode(user, "ASCII"));
     }
     OutputStream out = resp.getOutputStream();
+    HttpClient client = httpClientBuilder.build();
     try {
       HttpResponse httpResp = client.execute(base);
       resp.setStatus(httpResp.getStatusLine().getStatusCode());
@@ -287,6 +338,10 @@ public class WebAppProxyServlet extends HttpServlet {
     return ((AppReportFetcher) getServletContext()
         .getAttribute(WebAppProxy.FETCHER_ATTRIBUTE)).getApplicationReport(id);
   }
+
+  private ProxyCA getProxyCA() {
+    return ((ProxyCA) getServletContext().getAttribute(WebAppProxy.PROXY_CA));
+  }
   
   private String getProxyHost() throws IOException {
     return ((String) getServletContext()
@@ -420,6 +475,10 @@ public class WebAppProxyServlet extends HttpServlet {
         return;
       }
 
+      if (checkHttpsStrictAndNotProvided(resp, trackingUri, conf)) {
+        return;
+      }
+
       String runningUser = applicationReport.getUser();
 
       if (checkUser && !runningUser.equals(remoteUser)) {
@@ -453,7 +512,7 @@ public class WebAppProxyServlet extends HttpServlet {
       if (userWasWarned && userApproved) {
         c = makeCheckCookie(id, true);
       }
-      proxyLink(req, resp, toFetch, c, getProxyHost(), method);
+      proxyLink(req, resp, toFetch, c, getProxyHost(), method, id);
 
     } catch(URISyntaxException | YarnException e) {
       throw new IOException(e); 

http://git-wip-us.apache.org/repos/asf/hadoop/blob/c2288ac4/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestProxyCA.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestProxyCA.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestProxyCA.java
new file mode 100644
index 0000000..67bcea2
--- /dev/null
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestProxyCA.java
@@ -0,0 +1,518 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.apache.hadoop.yarn.server.webproxy;
+
+import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
+import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+public class TestProxyCA {
+
+  @Test
+  public void testInit() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    Assert.assertNull(proxyCA.getCaCert());
+    Assert.assertNull(proxyCA.getCaKeyPair());
+    Assert.assertNull(proxyCA.getX509KeyManager());
+    Assert.assertNull(proxyCA.getHostnameVerifier());
+
+    proxyCA.init();
+    Assert.assertNotNull(proxyCA.getCaCert());
+    Assert.assertNotNull(proxyCA.getCaKeyPair());
+    Assert.assertNotNull(proxyCA.getX509KeyManager());
+    Assert.assertNotNull(proxyCA.getHostnameVerifier());
+  }
+
+  @Test
+  public void testCreateChildKeyStore() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    byte[] keystoreBytes = proxyCA.createChildKeyStore(appId,
+        "password");
+    KeyStore keyStore = KeyStoreTestUtil.bytesToKeyStore(keystoreBytes,
+        "password");
+    Assert.assertEquals(1, keyStore.size());
+    Certificate[] certChain = keyStore.getCertificateChain("server");
+    Assert.assertEquals(2, certChain.length);
+    X509Certificate caCert = (X509Certificate) certChain[1];
+    X509Certificate cert = (X509Certificate) certChain[0];
+
+    // check child cert
+    Assert.assertEquals(caCert.getSubjectX500Principal().toString(),
+        cert.getIssuerDN().toString());
+    Assert.assertEquals(new X500Principal("CN=" + appId),
+        cert.getSubjectX500Principal());
+    Assert.assertFalse("Found multiple fields in X500 Principal, when there " +
+            "should have only been one: " + cert.getSubjectX500Principal(),
+        cert.getSubjectX500Principal().toString().contains(","));
+    Assert.assertEquals("SHA512withRSA", cert.getSigAlgName());
+    Assert.assertEquals(cert.getNotBefore(), cert.getNotAfter());
+    Assert.assertTrue("Expected certificate to be expired but was not: "
+        + cert.getNotAfter(), cert.getNotAfter().before(new Date()));
+    Assert.assertEquals(new X500Principal("CN=" + appId).toString(),
+        cert.getSubjectDN().toString());
+    Key privateKey = keyStore.getKey("server", "password".toCharArray());
+    Assert.assertEquals("RSA", privateKey.getAlgorithm());
+    Assert.assertEquals(-1, cert.getBasicConstraints());
+
+    // verify signature on child cert
+    PublicKey caPublicKey = caCert.getPublicKey();
+    cert.verify(caPublicKey);
+
+    // check CA cert
+    checkCACert(caCert);
+    Assert.assertEquals(proxyCA.getCaCert(), caCert);
+
+    // verify signature on CA cert
+    caCert.verify(caPublicKey);
+
+    // verify CA public key matches private key
+    PrivateKey caPrivateKey =
+        proxyCA.getX509KeyManager().getPrivateKey(null);
+    checkPrivatePublicKeys(caPrivateKey, caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPublic(), caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPrivate(), caPrivateKey);
+  }
+
+  @Test
+  public void testGetChildTrustStore() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    byte[] truststoreBytes = proxyCA.getChildTrustStore("password");
+    KeyStore truststore = KeyStoreTestUtil.bytesToKeyStore(truststoreBytes,
+        "password");
+    Assert.assertEquals(1, truststore.size());
+    X509Certificate caCert =
+        (X509Certificate) truststore.getCertificate("client");
+
+    // check CA cert
+    checkCACert(caCert);
+    Assert.assertEquals(proxyCA.getCaCert(), caCert);
+
+    // verify signature on CA cert
+    PublicKey caPublicKey = caCert.getPublicKey();
+    caCert.verify(caPublicKey);
+
+    // verify CA public key matches private key
+    PrivateKey caPrivateKey =
+        proxyCA.getX509KeyManager().getPrivateKey(null);
+    checkPrivatePublicKeys(caPrivateKey, caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPublic(), caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPrivate(), caPrivateKey);
+  }
+
+  @Test
+  public void testGenerateKeyStorePassword() throws Exception {
+    // We can't possibly test every possible string, but we can at least verify
+    // a few things about a few of the generated strings as a sanity check
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    Set<String> passwords = new HashSet<>();
+
+    for (int i = 0; i < 5; i++) {
+      String password = proxyCA.generateKeyStorePassword();
+      Assert.assertEquals(16, password.length());
+      for (char c : password.toCharArray()) {
+        Assert.assertFalse("Found character '" + c + "' in password '"
+            + password + "' which is outside of the expected range", c < ' ');
+        Assert.assertFalse("Found character '" + c + "' in password '"
+            + password + "' which is outside of the expected range", c > 'z');
+      }
+      Assert.assertFalse("Password " + password
+          + " was generated twice, which is _extremely_ unlikely"
+          + " and shouldn't practically happen: " + passwords,
+          passwords.contains(password));
+      passwords.add(password);
+    }
+  }
+
+  @Test
+  public void testCreateTrustManagerDefaultTrustManager() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+    Mockito.when(defaultTrustManager.getAcceptedIssuers()).thenReturn(
+        new X509Certificate[]{KeyStoreTestUtil.generateCertificate(
+            "CN=foo", KeyStoreTestUtil.generateKeyPair("RSA"), 30,
+            "SHA1withRSA")});
+
+    Assert.assertArrayEquals(defaultTrustManager.getAcceptedIssuers(),
+        trustManager.getAcceptedIssuers());
+    trustManager.checkClientTrusted(null, null);
+  }
+
+  @Test
+  public void testCreateTrustManagerYarnCert() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+
+    X509Certificate[] certChain = castCertificateArrayToX509CertificateArray(
+        KeyStoreTestUtil.bytesToKeyStore(
+            proxyCA.createChildKeyStore(appId, "password"), "password")
+            .getCertificateChain("server"));
+    trustManager.checkServerTrusted(certChain, "RSA");
+    Mockito.verify(defaultTrustManager, Mockito.times(0))
+        .checkServerTrusted(certChain, "RSA");
+  }
+
+  @Test
+  public void testCreateTrustManagerWrongApp() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    ApplicationId appId2 =
+        ApplicationId.newInstance(System.currentTimeMillis(), 2);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+
+    X509Certificate[] certChain = castCertificateArrayToX509CertificateArray(
+        KeyStoreTestUtil.bytesToKeyStore(
+            proxyCA.createChildKeyStore(appId2, "password"), "password")
+            .getCertificateChain("server"));
+    try {
+      trustManager.checkServerTrusted(certChain, "RSA");
+      Assert.fail("Should have thrown a CertificateException, but did not");
+    } catch (CertificateException ce) {
+      Assert.assertEquals("Expected to find Subject X500 Principal with CN=" +
+          appId + " but found CN=" + appId2, ce.getMessage());
+    }
+  }
+
+  @Test
+  public void testCreateTrustManagerWrongRM() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+
+    ProxyCA proxyCA2 = new ProxyCA(); // Simulates another RM
+    proxyCA2.init();
+    X509Certificate[] certChain = castCertificateArrayToX509CertificateArray(
+        KeyStoreTestUtil.bytesToKeyStore(
+            proxyCA2.createChildKeyStore(appId, "password"), "password")
+            .getCertificateChain("server"));
+    Mockito.verify(defaultTrustManager, Mockito.times(0))
+        .checkServerTrusted(certChain, "RSA");
+    trustManager.checkServerTrusted(certChain, "RSA");
+    Mockito.verify(defaultTrustManager, Mockito.times(1))
+        .checkServerTrusted(certChain, "RSA");
+  }
+
+  @Test
+  public void testCreateTrustManagerRealCert() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+
+    // "real" cert
+    X509Certificate[]
+        certChain = new X509Certificate[]{
+        KeyStoreTestUtil.generateCertificate("CN=foo.com",
+            KeyStoreTestUtil.generateKeyPair("RSA"), 30, "SHA1withRSA")};
+    Mockito.verify(defaultTrustManager, Mockito.times(0))
+        .checkServerTrusted(certChain, "RSA");
+    trustManager.checkServerTrusted(certChain, "RSA");
+    Mockito.verify(defaultTrustManager, Mockito.times(1))
+        .checkServerTrusted(certChain, "RSA");
+
+    // "real" cert x2
+    certChain = new X509Certificate[]{
+        KeyStoreTestUtil.generateCertificate("CN=foo.com",
+            KeyStoreTestUtil.generateKeyPair("RSA"), 30, "SHA1withRSA"),
+        KeyStoreTestUtil.generateCertificate("CN=foo.com",
+            KeyStoreTestUtil.generateKeyPair("RSA"), 30, "SHA1withRSA")};
+    Mockito.verify(defaultTrustManager, Mockito.times(0))
+        .checkServerTrusted(certChain, "RSA");
+    trustManager.checkServerTrusted(certChain, "RSA");
+    Mockito.verify(defaultTrustManager, Mockito.times(1))
+        .checkServerTrusted(certChain, "RSA");
+  }
+
+  @Test
+  public void testCreateTrustManagerExceptions() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509TrustManager defaultTrustManager = 
Mockito.mock(X509TrustManager.class);
+    proxyCA.setDefaultTrustManager(defaultTrustManager);
+    ApplicationId appId =
+        ApplicationId.newInstance(System.currentTimeMillis(), 1);
+    X509TrustManager trustManager = proxyCA.createTrustManager(appId);
+
+    for (Exception e : new Exception[]{
+        new CertificateException(), new NoSuchAlgorithmException(),
+        new InvalidKeyException(), new SignatureException(),
+        new NoSuchProviderException()}) {
+      X509Certificate[] certChain = castCertificateArrayToX509CertificateArray(
+          KeyStoreTestUtil.bytesToKeyStore(
+              proxyCA.createChildKeyStore(appId, "password"), "password")
+              .getCertificateChain("server"));
+      X509Certificate cert = Mockito.spy(certChain[0]);
+      certChain[0] = cert;
+      // Throw e to simulate problems with verifying
+      Mockito.doThrow(e).when(certChain[0]).verify(Mockito.any());
+      Mockito.verify(defaultTrustManager, Mockito.times(0))
+          .checkServerTrusted(certChain, "RSA");
+      trustManager.checkServerTrusted(certChain, "RSA");
+      Mockito.verify(defaultTrustManager, Mockito.times(1))
+          .checkServerTrusted(certChain, "RSA");
+    }
+  }
+
+  @Test
+  public void testCreateKeyManager() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    X509KeyManager keyManager = proxyCA.getX509KeyManager();
+
+    Assert.assertArrayEquals(new String[]{"client"},
+        keyManager.getClientAliases(null, null));
+    Assert.assertEquals("client",
+        keyManager.chooseClientAlias(null, null, null));
+    Assert.assertNull(keyManager.getServerAliases(null, null));
+    Assert.assertNull(keyManager.chooseServerAlias(null, null, null));
+
+    byte[] truststoreBytes = proxyCA.getChildTrustStore("password");
+    KeyStore truststore = KeyStoreTestUtil.bytesToKeyStore(truststoreBytes,
+        "password");
+    Assert.assertEquals(1, truststore.size());
+    X509Certificate caCert =
+        (X509Certificate) truststore.getCertificate("client");
+    Assert.assertArrayEquals(new X509Certificate[]{caCert},
+        keyManager.getCertificateChain(null));
+    Assert.assertEquals(proxyCA.getCaCert(), caCert);
+
+    PrivateKey caPrivateKey = keyManager.getPrivateKey(null);
+    PublicKey caPublicKey = caCert.getPublicKey();
+    checkPrivatePublicKeys(caPrivateKey, caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPublic(), caPublicKey);
+    Assert.assertEquals(proxyCA.getCaKeyPair().getPrivate(), caPrivateKey);
+  }
+
+  @Test
+  public void testCreateHostnameVerifier() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    SSLSession sslSession = Mockito.mock(SSLSession.class);
+    Mockito.when(sslSession.getPeerCertificates()).thenReturn(
+        KeyStoreTestUtil.bytesToKeyStore(
+            proxyCA.createChildKeyStore(
+                ApplicationId.newInstance(System.currentTimeMillis(), 1),
+                "password"), "password").getCertificateChain("server"));
+    Assert.assertTrue(verifier.verify("foo", sslSession));
+  }
+
+  @Test
+  public void testCreateHostnameVerifierSSLPeerUnverifiedException()
+      throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    SSLSession sslSession = Mockito.mock(SSLSession.class);
+    Mockito.when(sslSession.getPeerCertificates()).thenThrow(
+        new SSLPeerUnverifiedException(""));
+    Assert.assertFalse(verifier.verify("foo", sslSession));
+  }
+
+  @Test
+  public void testCreateHostnameVerifierWrongRM() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    SSLSession sslSession = Mockito.mock(SSLSession.class);
+    ProxyCA proxyCA2 = new ProxyCA(); // Simulate another RM
+    proxyCA2.init();
+    Mockito.when(sslSession.getPeerCertificates()).thenReturn(
+        KeyStoreTestUtil.bytesToKeyStore(
+            proxyCA2.createChildKeyStore(
+                ApplicationId.newInstance(System.currentTimeMillis(), 1),
+                "password"), "password").getCertificateChain("server"));
+    Assert.assertFalse(verifier.verify("foo", sslSession));
+  }
+
+  @Test
+  public void testCreateHostnameVerifierExceptions() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    for (Exception e : new Exception[]{
+        new CertificateException(), new NoSuchAlgorithmException(),
+        new InvalidKeyException(), new SignatureException(),
+        new NoSuchProviderException()}) {
+      SSLSession sslSession = Mockito.mock(SSLSession.class);
+      Mockito.when(sslSession.getPeerCertificates()).thenAnswer(
+          new Answer<Certificate[]>() {
+            @Override
+            public Certificate[] answer(InvocationOnMock invocation)
+                throws Throwable {
+              Certificate[] certChain = KeyStoreTestUtil.bytesToKeyStore(
+                  proxyCA.createChildKeyStore(
+                      ApplicationId.newInstance(System.currentTimeMillis(), 1),
+                      "password"), "password").getCertificateChain("server");
+              Certificate cert = Mockito.spy(certChain[0]);
+              certChain[0] = cert;
+              // Throw e to simulate problems with verifying
+              Mockito.doThrow(e).when(cert).verify(Mockito.any());
+              return certChain;
+            }
+          });
+      Assert.assertFalse(verifier.verify("foo", sslSession));
+    }
+  }
+
+  @Test
+  public void testCreateHostnameVerifierRealCert() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    SSLSession sslSession = Mockito.mock(SSLSession.class);
+    Mockito.when(sslSession.getPeerCertificates()).thenAnswer(
+        new Answer<Certificate[]>() {
+          @Override
+          public Certificate[] answer(InvocationOnMock invocation)
+              throws Throwable {
+            // "real" cert
+            Certificate[] certChain = new Certificate[]{
+                KeyStoreTestUtil.generateCertificate("CN=foo.com",
+                    KeyStoreTestUtil.generateKeyPair("RSA"), 30, "SHA1withRSA")
+            };
+            return certChain;
+          }
+        });
+    Assert.assertTrue(verifier.verify("foo.com", sslSession));
+  }
+
+  @Test
+  public void testCreateHostnameVerifierRealCertBad() throws Exception {
+    ProxyCA proxyCA = new ProxyCA();
+    proxyCA.init();
+    HostnameVerifier verifier = proxyCA.getHostnameVerifier();
+
+    SSLSession sslSession = Mockito.mock(SSLSession.class);
+    Mockito.when(sslSession.getPeerCertificates()).thenAnswer(
+        new Answer<Certificate[]>() {
+          @Override
+          public Certificate[] answer(InvocationOnMock invocation)
+              throws Throwable {
+            // "real" cert
+            Certificate[] certChain = new Certificate[]{
+                KeyStoreTestUtil.generateCertificate("CN=foo.com",
+                    KeyStoreTestUtil.generateKeyPair("RSA"), 30, "SHA1withRSA")
+            };
+            return certChain;
+          }
+        });
+    Assert.assertFalse(verifier.verify("bar.com", sslSession));
+  }
+
+  private void checkCACert(X509Certificate caCert) {
+    Assert.assertEquals(caCert.getSubjectX500Principal().toString(),
+        caCert.getIssuerDN().toString());
+    Assert.assertEquals(caCert.getSubjectX500Principal().toString(),
+        caCert.getSubjectDN().toString());
+    Assert.assertTrue("Expected CA certificate X500 Principal to start with" +
+            " 'OU=YARN-', but did not: " + caCert.getSubjectX500Principal(),
+        caCert.getSubjectX500Principal().toString().startsWith("OU=YARN-"));
+    Assert.assertFalse("Found multiple fields in X500 Principal, when there " +
+            "should have only been one: " + caCert.getSubjectX500Principal(),
+        caCert.getSubjectX500Principal().toString().contains(","));
+    Assert.assertEquals("SHA512withRSA", caCert.getSigAlgName());
+    Assert.assertEquals(
+        new GregorianCalendar(2037, Calendar.DECEMBER, 31).getTime(),
+        caCert.getNotAfter());
+    Assert.assertTrue("Expected certificate to have started but was not: "
+        + caCert.getNotBefore(), caCert.getNotBefore().before(new Date()));
+    Assert.assertEquals(0, caCert.getBasicConstraints());
+  }
+
+  private void checkPrivatePublicKeys(PrivateKey privateKey,
+      PublicKey publicKey) throws NoSuchAlgorithmException, 
InvalidKeyException,
+      SignatureException {
+    byte[] data = new byte[2000];
+    new Random().nextBytes(data);
+    Signature signer = Signature.getInstance("SHA512withRSA");
+    signer.initSign(privateKey);
+    signer.update(data);
+    byte[] sig = signer.sign();
+    signer = Signature.getInstance("SHA512withRSA");
+    signer.initVerify(publicKey);
+    signer.update(data);
+    Assert.assertTrue(signer.verify(sig));
+  }
+
+  private X509Certificate[] castCertificateArrayToX509CertificateArray(
+      Certificate[] certs) {
+    return Arrays.copyOf(certs, certs.length, X509Certificate[].class);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/c2288ac4/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestWebAppProxyServlet.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestWebAppProxyServlet.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestWebAppProxyServlet.java
index fc97387..f04bc9a 100644
--- 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestWebAppProxyServlet.java
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-web-proxy/src/test/java/org/apache/hadoop/yarn/server/webproxy/TestWebAppProxyServlet.java
@@ -27,6 +27,8 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.net.ConnectException;
 import java.net.HttpCookie;
 import java.net.HttpURLConnection;
@@ -54,6 +56,7 @@ import 
org.apache.hadoop.yarn.api.records.impl.pb.ApplicationReportPBImpl;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException;
 import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.webapp.MimeType;
 import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -63,6 +66,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.servlet.ServletHolder;
+import org.mockito.Mockito;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -333,12 +337,13 @@ public class TestWebAppProxyServlet {
       assertEquals(proxyConn.getRequestProperties().size(), 4);
       proxyConn.connect();
       assertEquals(HttpURLConnection.HTTP_OK, proxyConn.getResponseCode());
-      // Verify if number of headers received by end server is 8.
-      // Eight headers include Accept, Host, Connection, User-Agent, Cookie,
-      // Origin, Access-Control-Request-Method and
+      // Verify if number of headers received by end server is 9.
+      // This should match WebAppProxyServlet#PASS_THROUGH_HEADERS.
+      // Nine headers include Accept, Host, Connection, User-Agent, Cookie,
+      // Origin, Access-Control-Request-Method, Accept-Encoding, and
       // Access-Control-Request-Headers. Pls note that Unknown-Header is 
dropped
       // by proxy as it is not in the list of allowed headers.
-      assertEquals(numberOfHeaders, 8);
+      assertEquals(numberOfHeaders, 9);
       assertFalse(hasUnknownHeader);
     } finally {
       proxy.close();
@@ -383,6 +388,51 @@ public class TestWebAppProxyServlet {
     }
   }
 
+  @Test(timeout=5000)
+  public void testCheckHttpsStrictAndNotProvided() throws Exception {
+    HttpServletResponse resp = Mockito.mock(HttpServletResponse.class);
+    StringWriter sw = new StringWriter();
+    Mockito.when(resp.getWriter()).thenReturn(new PrintWriter(sw));
+    YarnConfiguration conf = new YarnConfiguration();
+    final URI httpLink = new URI("http://foo.com";);
+    final URI httpsLink = new URI("https://foo.com";);
+
+    // NONE policy
+    conf.set(YarnConfiguration.RM_APPLICATION_HTTPS_POLICY, "NONE");
+    assertFalse(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpsLink, conf));
+    assertEquals("", sw.toString());
+    Mockito.verify(resp, Mockito.times(0)).setContentType(Mockito.any());
+    assertFalse(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpLink, conf));
+    assertEquals("", sw.toString());
+    Mockito.verify(resp, Mockito.times(0)).setContentType(Mockito.any());
+
+    // LENIENT policy
+    conf.set(YarnConfiguration.RM_APPLICATION_HTTPS_POLICY, "LENIENT");
+    assertFalse(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpsLink, conf));
+    assertEquals("", sw.toString());
+    Mockito.verify(resp, Mockito.times(0)).setContentType(Mockito.any());
+    assertFalse(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpLink, conf));
+    assertEquals("", sw.toString());
+    Mockito.verify(resp, Mockito.times(0)).setContentType(Mockito.any());
+
+    // STRICT policy
+    conf.set(YarnConfiguration.RM_APPLICATION_HTTPS_POLICY, "STRICT");
+    assertFalse(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpsLink, conf));
+    assertEquals("", sw.toString());
+    Mockito.verify(resp, Mockito.times(0)).setContentType(Mockito.any());
+    assertTrue(WebAppProxyServlet.checkHttpsStrictAndNotProvided(
+        resp, httpLink, conf));
+    String s = sw.toString();
+    assertTrue("Was expecting an HTML page explaining that an HTTPS tracking" +
+        " url must be used but found " + s, s.contains("HTTPS must be used"));
+    Mockito.verify(resp, Mockito.times(1)).setContentType(MimeType.HTML);
+  }
+
   private String readInputStream(InputStream input) throws Exception {
     ByteArrayOutputStream data = new ByteArrayOutputStream();
     byte[] buffer = new byte[512];


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org
For additional commands, e-mail: common-commits-h...@hadoop.apache.org

Reply via email to