Skip to content

Commit

Permalink
Support -cert and -noCertificateCheck in WebSocket mode (#690)
Browse files Browse the repository at this point in the history
  • Loading branch information
basil authored Oct 24, 2023
1 parent 920a09d commit 507a8ba
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 33 deletions.
45 changes: 37 additions & 8 deletions src/main/java/hudson/remoting/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.security.NoSuchProviderException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
Expand Down Expand Up @@ -76,7 +77,11 @@
import jakarta.websocket.EndpointConfig;
import jakarta.websocket.HandshakeResponse;
import jakarta.websocket.Session;
import jakarta.websocket.WebSocketContainer;
import net.jcip.annotations.NotThreadSafe;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.jenkinsci.remoting.engine.Jnlp4ConnectionState;
import org.jenkinsci.remoting.engine.JnlpAgentEndpoint;
import org.jenkinsci.remoting.engine.JnlpAgentEndpointConfigurator;
Expand All @@ -94,6 +99,8 @@
import org.jenkinsci.remoting.protocol.impl.ConnectionRefusalException;
import org.jenkinsci.remoting.util.KeyUtils;
import org.jenkinsci.remoting.util.VersionNumber;
import org.jenkinsci.remoting.util.https.NoCheckHostnameVerifier;
import org.jenkinsci.remoting.util.https.NoCheckTrustManager;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

Expand Down Expand Up @@ -682,7 +689,19 @@ public void closeRead() throws IOException {
}
hudsonUrl = candidateUrls.get(0);
String wsUrl = hudsonUrl.toString().replaceFirst("^http", "ws");
ContainerProvider.getWebSocketContainer().connectToServer(new AgentEndpoint(),
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
if (container instanceof ClientManager) {
ClientManager client = (ClientManager) container;
SSLContext sslContext = getSSLContext(candidateCertificates, disableHttpsCertValidation);
if (sslContext != null) {
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(sslContext);
if (disableHttpsCertValidation) {
sslEngineConfigurator.setHostnameVerifier(new NoCheckHostnameVerifier());
}
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
}
}
container.connectToServer(new AgentEndpoint(),
ClientEndpointConfig.Builder.create().configurator(headerHandler).build(), URI.create(wsUrl + "wsagents/"));
while (ch.get() == null) {
Thread.sleep(100);
Expand Down Expand Up @@ -887,7 +906,7 @@ private JnlpEndpointResolver createEndpointResolver(List<String> jenkinsUrls, St
if (directConnection == null) {
SSLSocketFactory sslSocketFactory = null;
try {
sslSocketFactory = getSSLSocketFactory(candidateCertificates);
sslSocketFactory = getSSLSocketFactory(candidateCertificates, disableHttpsCertValidation);
} catch (Exception e) {
events.error(e);
}
Expand Down Expand Up @@ -1037,12 +1056,14 @@ private static FileInputStream getFileInputStream(final File file) throws Privil
}

@CheckForNull
@Restricted(NoExternalUse.class)
static SSLSocketFactory getSSLSocketFactory(List<X509Certificate> x509Certificates)
private static SSLContext getSSLContext(List<X509Certificate> x509Certificates, boolean noCertificateCheck)
throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException,
NoSuchAlgorithmException, IOException, KeyManagementException {
SSLSocketFactory sslSocketFactory = null;
if (x509Certificates != null && !x509Certificates.isEmpty()) {
SSLContext sslContext = null;
if (noCertificateCheck) {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new NoCheckTrustManager()}, new SecureRandom());
} else if (x509Certificates != null && !x509Certificates.isEmpty()) {
KeyStore keyStore = getCacertsKeyStore();
// load the keystore
keyStore.load(null, null);
Expand All @@ -1058,11 +1079,19 @@ static SSLSocketFactory getSSLSocketFactory(List<X509Certificate> x509Certificat
SSLContext ctx = SSLContext.getInstance("TLS");
// now we have our custom socket factory
ctx.init(null, trustManagerFactory.getTrustManagers(), null);
sslSocketFactory = ctx.getSocketFactory();
}
return sslSocketFactory;
return sslContext;
}

@CheckForNull
@Restricted(NoExternalUse.class)
static SSLSocketFactory getSSLSocketFactory(List<X509Certificate> x509Certificates, boolean noCertificateCheck)
throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException,
NoSuchAlgorithmException, IOException, KeyManagementException {
SSLContext sslContext = getSSLContext(x509Certificates, noCertificateCheck);
return sslContext == null ? null : sslContext.getSocketFactory();
}

/**
* Socket read timeout.
* A {@link SocketInputStream#read()} call associated with underlying Socket will block for only this amount of time
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/hudson/remoting/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,6 @@ public void setNoCertificateCheck(boolean ignored) throws NoSuchAlgorithmExcepti
"-tunnel",
"-credentials",
"-proxyCredentials",
"-cert",
"-noCertificateCheck",
"-noKeepAlive"
})
public boolean webSocket;
Expand Down Expand Up @@ -409,7 +407,7 @@ public void run() throws CmdLineException, IOException, InterruptedException {

createX509Certificates();
try {
sslSocketFactory = Engine.getSSLSocketFactory(x509Certificates);
sslSocketFactory = Engine.getSSLSocketFactory(x509Certificates, noCertificateCheck);
} catch (GeneralSecurityException | PrivilegedActionException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@
import hudson.remoting.NoProxyEvaluator;
import org.jenkinsci.remoting.util.VersionNumber;
import org.jenkinsci.remoting.util.https.NoCheckHostnameVerifier;
import org.jenkinsci.remoting.util.https.NoCheckTrustManager;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.IOException;
import java.net.Authenticator;
import java.net.ConnectException;
Expand All @@ -57,9 +54,6 @@
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
Expand Down Expand Up @@ -557,24 +551,12 @@ public static URLConnection openURLConnection(URL url, String credentials, Strin

if (con instanceof HttpsURLConnection) {
final HttpsURLConnection httpsConnection = (HttpsURLConnection) con;
if (sslSocketFactory != null) {
httpsConnection.setSSLSocketFactory(sslSocketFactory);
}
if (disableHttpsCertValidation) {
LOGGER.log(Level.WARNING, "HTTPs certificate check is disabled for the endpoint.");

try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{new NoCheckTrustManager()}, new SecureRandom());
sslSocketFactory = ctx.getSocketFactory();

httpsConnection.setHostnameVerifier(new NoCheckHostnameVerifier());
httpsConnection.setSSLSocketFactory(sslSocketFactory);
} catch (KeyManagementException | NoSuchAlgorithmException ex) {
// We could just suppress it, but the exception will unlikely happen.
// So let's just propagate the error and fail the resolution
throw new IOException("Cannot initialize the insecure HTTPs mode", ex);
}

} else if (sslSocketFactory != null) {
httpsConnection.setSSLSocketFactory(sslSocketFactory);
httpsConnection.setHostnameVerifier(new NoCheckHostnameVerifier());
}
}
return con;
Expand Down

0 comments on commit 507a8ba

Please sign in to comment.