Skip to content

Commit

Permalink
[JENKINS-31256] Use credentials in waitForServerToBack (#87)
Browse files Browse the repository at this point in the history
* [JENKINS-31256] Use credentials in waitForServerToBack
This address three regressions introduced with HUDSON-4071, 662b0f and JENKINS-6167 as these only modified run() resulting in no proxy and no authorization support in waitForServerToBack()

* Move authorization code to openURLConnection()

* Factored out sslSocketFactory creation and use sslSocketFactory also in waitForServerToBack()
  • Loading branch information
oleg-nenashev committed Jun 9, 2016
1 parent f18c44e commit fbb9aff
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 36 deletions.
70 changes: 35 additions & 35 deletions src/main/java/hudson/remoting/Engine.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -214,46 +214,15 @@ 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();
if(!s.endsWith("/")) s+='/';
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);
Expand Down Expand Up @@ -441,6 +410,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) {
Expand All @@ -452,7 +427,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();
Expand Down Expand Up @@ -578,6 +553,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;
}
//a read() call on the SocketInputStream associated with underlying Socket will block for only this amount of time
static final int SOCKET_TIMEOUT = Integer.getInteger(Engine.class.getName()+".socketTimeout",30*60*1000);
/**
Expand Down
33 changes: 32 additions & 1 deletion src/main/java/hudson/remoting/Util.java
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -159,8 +161,9 @@ static boolean inNoProxyEnvVar(String host) {
/**
* 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) {
Expand All @@ -180,9 +183,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<Proxy> proxies = ProxySelector.getDefault().select(URI.create(String.format("http://%s:%d", host, port))).iterator();
Expand Down

0 comments on commit fbb9aff

Please sign in to comment.