diff --git a/src/main/java/hudson/remoting/Engine.java b/src/main/java/hudson/remoting/Engine.java index f28891c35..00f7956e5 100644 --- a/src/main/java/hudson/remoting/Engine.java +++ b/src/main/java/hudson/remoting/Engine.java @@ -29,6 +29,7 @@ import java.security.AccessController; import java.security.KeyStore; import java.security.KeyStoreException; +import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivilegedActionException; @@ -42,7 +43,6 @@ import java.util.logging.Level; import javax.annotation.CheckForNull; import javax.annotation.concurrent.NotThreadSafe; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; @@ -214,25 +214,7 @@ public void run() { Throwable firstError=null; String host=null; String port=null; - SSLSocketFactory sslSocketFactory = null; - if (candidateCertificates != null && !candidateCertificates.isEmpty()) { - KeyStore keyStore = getCacertsKeyStore(); - // load the keystore - keyStore.load(null, null); - int i = 0; - for (X509Certificate c : candidateCertificates) { - keyStore.setCertificateEntry(String.format("alias-%d", i++), c); - } - // prepare the trust manager - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keyStore); - // prepare the SSL context - SSLContext ctx = SSLContext.getInstance("TLS"); - ctx.init(null, trustManagerFactory.getTrustManagers(), null); - // now we have our custom socket factory - sslSocketFactory = ctx.getSocketFactory(); - } + SSLSocketFactory sslSocketFactory = getSSLSocketFactory(); for (URL url : candidateUrls) { String s = url.toExternalForm(); @@ -240,20 +222,7 @@ public void run() { URL salURL = new URL(s+"tcpSlaveAgentListener/"); // find out the TCP port - HttpURLConnection con = (HttpURLConnection)Util.openURLConnection(salURL); - if (con instanceof HttpsURLConnection && sslSocketFactory != null) { - ((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory); - } - if (credentials != null) { - // TODO /tcpSlaveAgentListener is unprotected so why do we need to pass any credentials? - String encoding = Base64.encode(credentials.getBytes("UTF-8")); - con.setRequestProperty("Authorization", "Basic " + encoding); - } - - if (proxyCredentials != null) { - String encoding = Base64.encode(proxyCredentials.getBytes("UTF-8")); - con.setRequestProperty("Proxy-Authorization", "Basic " + encoding); - } + HttpURLConnection con = (HttpURLConnection)Util.openURLConnection(salURL, credentials, proxyCredentials, sslSocketFactory); try { try { con.setConnectTimeout(30000); @@ -424,6 +393,12 @@ private Socket connect(String host, String port) throws IOException, Interrupted private void waitForServerToBack() throws InterruptedException { Thread t = Thread.currentThread(); String oldName = t.getName(); + SSLSocketFactory sslSocketFactory = null; + try { + sslSocketFactory = getSSLSocketFactory(); + } catch (Throwable e) { + events.error(e); + } try { int retries=0; while(true) { @@ -435,7 +410,7 @@ private void waitForServerToBack() throws InterruptedException { retries++; t.setName(oldName+": trying "+url+" for "+retries+" times"); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpURLConnection con = (HttpURLConnection)Util.openURLConnection(url, credentials, proxyCredentials, sslSocketFactory); con.setConnectTimeout(5000); con.setReadTimeout(5000); con.connect(); @@ -562,6 +537,31 @@ public FileInputStream run() throws Exception { }); } + private SSLSocketFactory getSSLSocketFactory() + throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException, + NoSuchAlgorithmException, IOException, KeyManagementException { + SSLSocketFactory sslSocketFactory = null; + if (candidateCertificates != null && !candidateCertificates.isEmpty()) { + KeyStore keyStore = getCacertsKeyStore(); + // load the keystore + keyStore.load(null, null); + int i = 0; + for (X509Certificate c : candidateCertificates) { + keyStore.setCertificateEntry(String.format("alias-%d", i++), c); + } + // prepare the trust manager + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + // prepare the SSL context + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(null, trustManagerFactory.getTrustManagers(), null); + // now we have our custom socket factory + sslSocketFactory = ctx.getSocketFactory(); + } + return sslSocketFactory; + } + /** * @deprecated Use {@link JnlpProtocol#GREETING_SUCCESS}. */ diff --git a/src/main/java/hudson/remoting/Util.java b/src/main/java/hudson/remoting/Util.java index 3716ecb26..fbb980810 100644 --- a/src/main/java/hudson/remoting/Util.java +++ b/src/main/java/hudson/remoting/Util.java @@ -14,6 +14,8 @@ import java.net.Proxy; import java.net.SocketAddress; import java.net.URL; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; import java.util.Iterator; /** @@ -110,8 +112,9 @@ static String indent(String s) { /** * Gets URL connection. * If http_proxy environment variable exists, the connection uses the proxy. + * Credentials can be passed e.g. to support running Jenkins behind a (reverse) proxy requiring authorization */ - static URLConnection openURLConnection(URL url) throws IOException { + static URLConnection openURLConnection(URL url, String credentials, String proxyCredentials, SSLSocketFactory sslSocketFactory) throws IOException { String httpProxy = null; // If http.proxyHost property exists, openConnection() uses it. if (System.getProperty("http.proxyHost") == null) { @@ -131,9 +134,37 @@ static URLConnection openURLConnection(URL url) throws IOException { } else { con = url.openConnection(); } + if (credentials != null) { + String encoding = Base64.encode(credentials.getBytes("UTF-8")); + con.setRequestProperty("Authorization", "Basic " + encoding); + } + if (proxyCredentials != null) { + String encoding = Base64.encode(proxyCredentials.getBytes("UTF-8")); + con.setRequestProperty("Proxy-Authorization", "Basic " + encoding); + } + if (con instanceof HttpsURLConnection && sslSocketFactory != null) { + ((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory); + } return con; } + /** + * Gets URL connection. + * If http_proxy environment variable exists, the connection uses the proxy. + * Credentials can be passed e.g. to support running Jenkins behind a (reverse) proxy requiring authorization + */ + static URLConnection openURLConnection(URL url, String credentials, String proxyCredentials) throws IOException { + return openURLConnection(url, credentials, proxyCredentials, null); + } + + /** + * Gets URL connection. + * If http_proxy environment variable exists, the connection uses the proxy. + */ + static URLConnection openURLConnection(URL url) throws IOException { + return openURLConnection(url, null, null, null); + } + static InetSocketAddress getResolvedHttpProxyAddress(String host, int port) throws IOException { InetSocketAddress targetAddress = null; Iterator proxies = ProxySelector.getDefault().select(URI.create(String.format("http://%s:%d", host, port))).iterator();