mirror of https://github.com/jenkinsci/jenkins.git
Friendlier handling of `DeploymentHandshakeException` from CLI in `-webSocket` mode (#9591)
This commit is contained in:
parent
fc73c2622a
commit
15e045f03d
|
@ -32,6 +32,7 @@ import hudson.cli.client.Messages;
|
||||||
import jakarta.websocket.ClientEndpointConfig;
|
import jakarta.websocket.ClientEndpointConfig;
|
||||||
import jakarta.websocket.Endpoint;
|
import jakarta.websocket.Endpoint;
|
||||||
import jakarta.websocket.EndpointConfig;
|
import jakarta.websocket.EndpointConfig;
|
||||||
|
import jakarta.websocket.HandshakeResponse;
|
||||||
import jakarta.websocket.Session;
|
import jakarta.websocket.Session;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -64,6 +65,7 @@ import javax.net.ssl.TrustManager;
|
||||||
import org.glassfish.tyrus.client.ClientManager;
|
import org.glassfish.tyrus.client.ClientManager;
|
||||||
import org.glassfish.tyrus.client.ClientProperties;
|
import org.glassfish.tyrus.client.ClientProperties;
|
||||||
import org.glassfish.tyrus.client.SslEngineConfigurator;
|
import org.glassfish.tyrus.client.SslEngineConfigurator;
|
||||||
|
import org.glassfish.tyrus.client.exception.DeploymentHandshakeException;
|
||||||
import org.glassfish.tyrus.container.jdk.client.JdkClientContainer;
|
import org.glassfish.tyrus.container.jdk.client.JdkClientContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -340,13 +342,19 @@ public class CLI {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Authenticator extends ClientEndpointConfig.Configurator {
|
class Authenticator extends ClientEndpointConfig.Configurator {
|
||||||
|
HandshakeResponse hr;
|
||||||
@Override
|
@Override
|
||||||
public void beforeRequest(Map<String, List<String>> headers) {
|
public void beforeRequest(Map<String, List<String>> headers) {
|
||||||
if (factory.authorization != null) {
|
if (factory.authorization != null) {
|
||||||
headers.put("Authorization", List.of(factory.authorization));
|
headers.put("Authorization", List.of(factory.authorization));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void afterResponse(HandshakeResponse hr) {
|
||||||
|
this.hr = hr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
var authenticator = new Authenticator();
|
||||||
|
|
||||||
ClientManager client = ClientManager.createClient(JdkClientContainer.class.getName()); // ~ ContainerProvider.getWebSocketContainer()
|
ClientManager client = ClientManager.createClient(JdkClientContainer.class.getName()); // ~ ContainerProvider.getWebSocketContainer()
|
||||||
client.getProperties().put(ClientProperties.REDIRECT_ENABLED, true); // https://tyrus-project.github.io/documentation/1.13.1/index/tyrus-proprietary-config.html#d0e1775
|
client.getProperties().put(ClientProperties.REDIRECT_ENABLED, true); // https://tyrus-project.github.io/documentation/1.13.1/index/tyrus-proprietary-config.html#d0e1775
|
||||||
|
@ -357,7 +365,21 @@ public class CLI {
|
||||||
sslEngineConfigurator.setHostnameVerifier((s, sslSession) -> true);
|
sslEngineConfigurator.setHostnameVerifier((s, sslSession) -> true);
|
||||||
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
|
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
|
||||||
}
|
}
|
||||||
Session session = client.connectToServer(new CLIEndpoint(), ClientEndpointConfig.Builder.create().configurator(new Authenticator()).build(), URI.create(url.replaceFirst("^http", "ws") + "cli/ws"));
|
Session session;
|
||||||
|
try {
|
||||||
|
session = client.connectToServer(new CLIEndpoint(), ClientEndpointConfig.Builder.create().configurator(authenticator).build(), URI.create(url.replaceFirst("^http", "ws") + "cli/ws"));
|
||||||
|
} catch (DeploymentHandshakeException x) {
|
||||||
|
System.err.println("CLI handshake failed with status code " + x.getHttpStatusCode());
|
||||||
|
if (authenticator.hr != null) {
|
||||||
|
for (var entry : authenticator.hr.getHeaders().entrySet()) {
|
||||||
|
// org.glassfish.tyrus.core.Utils.parseHeaderValue improperly splits values like Date at commas, so undo that:
|
||||||
|
System.err.println(entry.getKey() + ": " + String.join(", ", entry.getValue()));
|
||||||
|
}
|
||||||
|
// UpgradeResponse.getReasonPhrase is useless since Jetty generates it from the code,
|
||||||
|
// and the body is not accessible at all.
|
||||||
|
}
|
||||||
|
return 15; // compare CLICommand.main
|
||||||
|
}
|
||||||
PlainCLIProtocol.Output out = new PlainCLIProtocol.Output() {
|
PlainCLIProtocol.Output out = new PlainCLIProtocol.Output() {
|
||||||
@Override
|
@Override
|
||||||
public void send(byte[] data) throws IOException {
|
public void send(byte[] data) throws IOException {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package hudson.cli;
|
package hudson.cli;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import hudson.Functions;
|
import hudson.Functions;
|
||||||
|
@ -131,6 +135,19 @@ public class CLIActionTest {
|
||||||
assertEquals(code, proc.join());
|
assertEquals(code, proc.join());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void authenticationFailed() throws Exception {
|
||||||
|
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
||||||
|
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
|
||||||
|
var jar = tmp.newFile("jenkins-cli.jar");
|
||||||
|
FileUtils.copyURLToFile(j.jenkins.getJnlpJars("jenkins-cli.jar").getURL(), jar);
|
||||||
|
var baos = new ByteArrayOutputStream();
|
||||||
|
var exitStatus = new Launcher.LocalLauncher(StreamTaskListener.fromStderr()).launch().cmds(
|
||||||
|
"java", "-jar", jar.getAbsolutePath(), "-s", j.getURL().toString(), "-auth", "user:bogustoken", "who-am-i"
|
||||||
|
).stdout(baos).start().join();
|
||||||
|
assertThat(baos.toString(), allOf(containsString("status code 401"), containsString("Server: Jetty")));
|
||||||
|
assertThat(exitStatus, is(15));
|
||||||
|
}
|
||||||
|
|
||||||
@Issue("JENKINS-41745")
|
@Issue("JENKINS-41745")
|
||||||
@Test
|
@Test
|
||||||
public void encodingAndLocale() throws Exception {
|
public void encodingAndLocale() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue