diff --git a/core/src/main/java/hudson/cli/CliProtocol.java b/core/src/main/java/hudson/cli/CliProtocol.java index cdf25b033ff0..58b5c95a6438 100644 --- a/core/src/main/java/hudson/cli/CliProtocol.java +++ b/core/src/main/java/hudson/cli/CliProtocol.java @@ -47,12 +47,17 @@ public String getName() { return jenkins.CLI.get().isEnabled() ? "CLI-connect" : null; } + @Override + public boolean isDeprecated() { + return true; + } + /** * {@inheritDoc} */ @Override public String getDisplayName() { - return "Jenkins CLI Protocol/1"; + return "Jenkins CLI Protocol/1 (deprecated, unencrypted)"; } @Override diff --git a/core/src/main/java/hudson/cli/CliProtocol2.java b/core/src/main/java/hudson/cli/CliProtocol2.java index e7d0bad71fa4..9fca4055fb10 100644 --- a/core/src/main/java/hudson/cli/CliProtocol2.java +++ b/core/src/main/java/hudson/cli/CliProtocol2.java @@ -38,12 +38,18 @@ public boolean isOptIn() { return false; } + @Override + public boolean isDeprecated() { + // We do not recommend it though it may be required for Remoting CLI + return true; + } + /** * {@inheritDoc} */ @Override public String getDisplayName() { - return "Jenkins CLI Protocol/2"; + return "Jenkins CLI Protocol/2 (deprecated)"; } @Override diff --git a/core/src/main/java/jenkins/AgentProtocol.java b/core/src/main/java/jenkins/AgentProtocol.java index 93140b71c152..f4917b399632 100644 --- a/core/src/main/java/jenkins/AgentProtocol.java +++ b/core/src/main/java/jenkins/AgentProtocol.java @@ -8,6 +8,8 @@ import java.io.IOException; import java.net.Socket; import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import jenkins.model.Jenkins; /** @@ -18,6 +20,15 @@ * Implementations of this extension point is singleton, and its {@link #handle(Socket)} method * gets invoked concurrently whenever a new connection comes in. * + *

Extending UI

+ *
+ *
description.jelly
+ *
Optional protocol description
+ *
deprecationCause.jelly
+ *
Optional. If the protocol is marked as {@link #isDeprecated()}, + * clarifies the deprecation reason and provides extra documentation links
+ *
+ * * @author Kohsuke Kawaguchi * @since 1.467 * @see TcpSlaveAgentListener @@ -53,6 +64,16 @@ public boolean isOptIn() { public boolean isRequired() { return false; } + + /** + * Checks if the protocol is deprecated. + * + * @since TODO + */ + public boolean isDeprecated() { + return false; + } + /** * Protocol name. * @@ -86,6 +107,7 @@ public static ExtensionList all() { return ExtensionList.lookup(AgentProtocol.class); } + @CheckForNull public static AgentProtocol of(String protocolName) { for (AgentProtocol p : all()) { String n = p.getName(); diff --git a/core/src/main/java/jenkins/install/SetupWizard.java b/core/src/main/java/jenkins/install/SetupWizard.java index 992ce935a769..0f04f903dbc9 100644 --- a/core/src/main/java/jenkins/install/SetupWizard.java +++ b/core/src/main/java/jenkins/install/SetupWizard.java @@ -52,6 +52,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; +import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import jenkins.CLI; @@ -62,6 +64,7 @@ import net.sf.json.JSONObject; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.jenkinsci.remoting.engine.JnlpProtocol4Handler; import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.stapler.interceptor.RequirePOST; @@ -127,6 +130,13 @@ public class SetupWizard extends PageDecorator { // Disable CLI over Remoting CLI.get().setEnabled(false); + // Disable old Non-Encrypted protocols () + HashSet newProtocols = new HashSet<>(jenkins.getAgentProtocols()); + newProtocols.removeAll(Arrays.asList( + "JNLP2-connect", "JNLP-connect", "CLI-connect" + )); + jenkins.setAgentProtocols(newProtocols); + // require a crumb issuer jenkins.setCrumbIssuer(new DefaultCrumbIssuer(false)); diff --git a/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java b/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java new file mode 100644 index 000000000000..096468e7b714 --- /dev/null +++ b/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java @@ -0,0 +1,113 @@ +/* + * The MIT License + * + * Copyright (c) 2017 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.slaves; + +import hudson.Extension; +import hudson.init.InitMilestone; +import hudson.init.Initializer; +import hudson.model.AdministrativeMonitor; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.CheckForNull; +import jenkins.AgentProtocol; +import jenkins.model.Jenkins; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + + +/** + * Monitors enabled protocols and warns if an {@link AgentProtocol} is deprecated. + * + * @author Oleg Nenashev + * @since TODO + * @see AgentProtocol + */ +@Extension +@Symbol("deprecatedAgentProtocol") +@Restricted(NoExternalUse.class) +public class DeprecatedAgentProtocolMonitor extends AdministrativeMonitor { + + private static final Logger LOGGER = Logger.getLogger(DeprecatedAgentProtocolMonitor.class.getName()); + + public DeprecatedAgentProtocolMonitor() { + super(); + } + + @Override + public String getDisplayName() { + return Messages.DeprecatedAgentProtocolMonitor_displayName(); + } + + @Override + public boolean isActivated() { + final Set agentProtocols = Jenkins.getInstance().getAgentProtocols(); + for (String name : agentProtocols) { + AgentProtocol pr = AgentProtocol.of(name); + if (pr != null && pr.isDeprecated()) { + return true; + } + } + return false; + } + + @Restricted(NoExternalUse.class) + public String getDeprecatedProtocols() { + String res = getDeprecatedProtocolsString(); + return res != null ? res : "N/A"; + } + + @CheckForNull + public static String getDeprecatedProtocolsString() { + final List deprecatedProtocols = new ArrayList<>(); + final Set agentProtocols = Jenkins.getInstance().getAgentProtocols(); + for (String name : agentProtocols) { + AgentProtocol pr = AgentProtocol.of(name); + if (pr != null && pr.isDeprecated()) { + deprecatedProtocols.add(name); + } + } + if (deprecatedProtocols.isEmpty()) { + return null; + } + return StringUtils.join(deprecatedProtocols, ','); + } + + @Initializer(after = InitMilestone.JOB_LOADED) + @Restricted(NoExternalUse.class) + public static void initializerCheck() { + String protocols = getDeprecatedProtocolsString(); + if(protocols != null) { + LOGGER.log(Level.WARNING, "This Jenkins instance uses deprecated Remoting protocols: {0}" + + "It may impact stability of the instance. " + + "If newer protocol versions are supported by all system components " + + "(agents, CLI and other clients), " + + "it is highly recommended to disable the deprecated protocols.", protocols); + } + } +} diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java index e351b93945ed..6c339506904b 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java @@ -79,6 +79,11 @@ public boolean isOptIn() { return OPT_IN; } + @Override + public boolean isDeprecated() { + return true; + } + @Override public String getName() { return handler.isEnabled() ? handler.getName() : null; diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java index 66bc07dc9d72..24aca6696f62 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java @@ -53,6 +53,11 @@ public boolean isOptIn() { return false; } + @Override + public boolean isDeprecated() { + return true; + } + /** * {@inheritDoc} */ diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java index 8d235f6114df..1614e5daf027 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java @@ -65,6 +65,11 @@ public String getDisplayName() { return Messages.JnlpSlaveAgentProtocol3_displayName(); } + @Override + public boolean isDeprecated() { + return true; + } + @Override public void handle(Socket socket) throws IOException, InterruptedException { handler.handle(socket, diff --git a/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.jelly b/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.jelly new file mode 100644 index 000000000000..9704ac6557ba --- /dev/null +++ b/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.jelly @@ -0,0 +1,4 @@ + + + ${%message} + diff --git a/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.properties b/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.properties new file mode 100644 index 000000000000..c46f5db25da9 --- /dev/null +++ b/core/src/main/resources/hudson/cli/CliProtocol/deprecationCause.properties @@ -0,0 +1,2 @@ +message=This protocol is an obsolete protocol, which has been replaced by CLI2-connect. \ + It is also not encrypted. diff --git a/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.jelly b/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.jelly new file mode 100644 index 000000000000..9704ac6557ba --- /dev/null +++ b/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.jelly @@ -0,0 +1,4 @@ + + + ${%message} + diff --git a/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.properties b/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.properties new file mode 100644 index 000000000000..8effec140412 --- /dev/null +++ b/core/src/main/resources/hudson/cli/CliProtocol2/deprecationCause.properties @@ -0,0 +1,3 @@ +message=Remoting-based CLI is deprecated and not recommended due to the security reasons. \ + It is recommended to disable this protocol on the instance. \ + if you need Remoting CLI on your instance, this protocol has to be enabled. diff --git a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy index 519143e4fdfc..9d1b0917e9fc 100644 --- a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy +++ b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy @@ -72,6 +72,11 @@ l.layout(norefresh:true, permission:app.ADMINISTER, title:my.displayName, csscla td(colspan:"2"); td(class:"setting-description"){ st.include(from:p, page: "description", optional:true); + if (p.deprecated) { + br() + text(b(_("Deprecated. "))) + st.include(from:p, page: "deprecationCause", optional:true); + } } td(); } diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly new file mode 100644 index 000000000000..3be67e2a95f0 --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly @@ -0,0 +1,7 @@ + + +
+ ${%blurb(it.deprecatedProtocols)} + ${%Protocol Configuration} +
+
diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties new file mode 100644 index 000000000000..b40c0b6cd63e --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties @@ -0,0 +1,4 @@ +blurb=This Jenkins instance uses deprecated protocols: {0}. \ + It may impact stability of the instance. \ + If newer protocol versions are supported by all system components (agents, CLI and other clients), \ + it is highly recommended to disable the deprecated protocols. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly new file mode 100644 index 000000000000..9704ac6557ba --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly @@ -0,0 +1,4 @@ + + + ${%message} + diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties new file mode 100644 index 000000000000..a50d4246fdd0 --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties @@ -0,0 +1,2 @@ +message=This protocol is an obsolete protocol, which has been replaced by JNLP2-connect. \ + It is also not encrypted. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly new file mode 100644 index 000000000000..b9c22be05f0f --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly @@ -0,0 +1,5 @@ + + + ${%message} + ${%JNLP2 Protocol Errata} + diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties new file mode 100644 index 000000000000..97e84785173f --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties @@ -0,0 +1,3 @@ +message=This protocol has known stability issues, and it is replaced by JNLP4. \ + It is also not encrypted. \ + See more information in the protocol Errata. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly new file mode 100644 index 000000000000..d9089b2f7df0 --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly @@ -0,0 +1,5 @@ + + + ${%This protocol is unstable. See the protocol documentation for more info.} + ${%JNLP3 Protocol Errata} + diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties @@ -0,0 +1 @@ + diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties index 3e5d49de58e3..ec1f6a2c89a4 100644 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties @@ -1,4 +1 @@ -summary=Extends the version 2 protocol by adding basic encryption but requires a thread per client. \ - This protocol falls back to Java Web Start Agent Protocol/2 (unencrypted) when it can't create a secure connection. \ - This protocol is not recommended. \ - Use Java Web Start Agent Protocol/4 instead. +summary=Extends the version 2 protocol by adding basic encryption but requires a thread per client. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties index 02dbda750874..6280077683ae 100644 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties @@ -20,6 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -summary=Erweitert das Protokoll Version 2 um einfache Verschl\u00FCsselung, aber erfordert einen Thread pro Client. \ - Dieses Protokoll f\u00E4llt auf Protokoll-Version 2 (unverschl\u00FCsselt) zur\u00FCck, wenn keine sichere Verbindung hergestellt werden kann. \ - Dieses Protokoll sollte nicht verwendet werden, stattdessen sollte Protokoll-Version 4 verwendet werden. +summary=Erweitert das Protokoll Version 2 um einfache Verschl\u00fcsselung, aber erfordert einen Thread pro Client. diff --git a/core/src/main/resources/jenkins/slaves/Messages.properties b/core/src/main/resources/jenkins/slaves/Messages.properties index 6cdab9261450..017247dbbd4d 100644 --- a/core/src/main/resources/jenkins/slaves/Messages.properties +++ b/core/src/main/resources/jenkins/slaves/Messages.properties @@ -20,7 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -JnlpSlaveAgentProtocol.displayName=Java Web Start Agent Protocol/1 (unencrypted) -JnlpSlaveAgentProtocol2.displayName=Java Web Start Agent Protocol/2 (unencrypted) -JnlpSlaveAgentProtocol3.displayName=Java Web Start Agent Protocol/3 (basic encryption) +JnlpSlaveAgentProtocol.displayName=Java Web Start Agent Protocol/1 (deprecated, unencrypted) +JnlpSlaveAgentProtocol2.displayName=Java Web Start Agent Protocol/2 (deprecated, unencrypted) +JnlpSlaveAgentProtocol3.displayName=Java Web Start Agent Protocol/3 (deprecated, basic encryption) JnlpSlaveAgentProtocol4.displayName=Java Web Start Agent Protocol/4 (TLS encryption) +DeprecatedAgentProtocolMonitor.displayName=Deprecated Agent Protocol Monitor diff --git a/test/src/test/java/jenkins/AgentProtocolTest.java b/test/src/test/java/jenkins/AgentProtocolTest.java new file mode 100644 index 000000000000..7deb30e74616 --- /dev/null +++ b/test/src/test/java/jenkins/AgentProtocolTest.java @@ -0,0 +1,156 @@ +/* + * The MIT License + * + * Copyright (c) 2017 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.annotation.CheckForNull; +import jenkins.install.SetupWizardTest; +import jenkins.model.Jenkins; +import jenkins.slaves.DeprecatedAgentProtocolMonitor; +import org.apache.commons.collections.ListUtils; +import org.apache.commons.lang.StringUtils; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import org.hamcrest.core.StringContains; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.LocalData; + +/** + * Tests for {@link AgentProtocol}. + * + * @author Oleg Nenashev + */ +public class AgentProtocolTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + + /** + * Checks that Jenkins does not disable agent protocols by default after the upgrade. + * + * @throws Exception Test failure + * @see SetupWizardTest#shouldDisableUnencryptedProtocolsByDefault() + */ + @Test + @LocalData + @Issue("JENKINS-45841") + public void testShouldNotDisableProtocolsForMigratedInstances() throws Exception { + assertProtocols(true, "Legacy Non-encrypted JNLP/CLI protocols should be enabled", + "JNLP-connect", "JNLP2-connect", "JNLP4-connect", "CLI-connect"); + assertProtocols(true, "Default encrypted protocols should be enabled", "JNLP4-connect", "CLI2-connect"); + assertProtocols(true, "Protocol should be enabled due to CLI settings", "CLI2-connect"); + assertProtocols(false, "JNLP3-connect protocol should be disabled by default", "JNLP3-connect"); + assertMonitorTriggered("JNLP-connect", "JNLP2-connect", "CLI-connect"); + } + + @Test + @LocalData + @Issue("JENKINS-45841") + public void testShouldNotOverrideUserConfiguration() throws Exception { + assertEnabled("CLI-connect", "JNLP-connect", "JNLP3-connect"); + assertDisabled("CLI2-connect", "JNLP2-connect", "JNLP4-connect"); + assertProtocols(true, "System protocols should be always enabled", "Ping"); + assertMonitorTriggered("JNLP-connect", "JNLP3-connect", "CLI-connect"); + } + + @Test + @LocalData + public void testShouldDisableCLIProtocolsWhenCLIisDisabled() throws Exception { + assertProtocols(false, "CLI is forcefully disabled, protocols should be blocked", + "CLI-connect", "CLI2-connect"); + assertEnabled("JNLP3-connect"); + assertMonitorTriggered("JNLP3-connect"); + } + + private void assertEnabled(String ... protocolNames) throws AssertionError { + assertProtocols(true, null, protocolNames); + } + + private void assertDisabled(String ... protocolNames) throws AssertionError { + assertProtocols(false, null, protocolNames); + } + + private void assertProtocols(boolean shouldBeEnabled, @CheckForNull String why, String ... protocolNames) { + assertProtocols(j.jenkins, shouldBeEnabled, why, protocolNames); + } + + public static void assertProtocols(Jenkins jenkins, boolean shouldBeEnabled, @CheckForNull String why, String ... protocolNames) + throws AssertionError { + Set agentProtocols = jenkins.getAgentProtocols(); + List failedChecks = new ArrayList<>(); + for (String protocol : protocolNames) { + if (shouldBeEnabled && !(agentProtocols.contains(protocol))) { + failedChecks.add(protocol); + } + if (!shouldBeEnabled && agentProtocols.contains(protocol)) { + failedChecks.add(protocol); + } + } + + if (!failedChecks.isEmpty()) { + String message = String.format("Protocol(s) are not %s: %s. %sEnabled protocols: %s", + shouldBeEnabled ? "enabled" : "disabled", + StringUtils.join(failedChecks, ','), + why != null ? "Reason: " + why + ". " : "", + StringUtils.join(agentProtocols, ',')); + fail(message); + } + } + + public static void assertMonitorNotActive() { + DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor(); + assertFalse("Deprecated Agent Protocol Monitor should not be activated", monitor.isActivated()); + } + + public static void assertMonitorTriggered(String ... expectedProtocols) { + DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor(); + assertTrue("Deprecated Agent Protocol Monitor should be activated", monitor.isActivated()); + String protocolList = monitor.getDeprecatedProtocols(); + assertThat("List of the protocols should not be null", protocolList, not(nullValue())); + + List failedChecks = new ArrayList<>(); + for(String protocol : expectedProtocols) { + if (!protocolList.contains(protocol)) { + failedChecks.add(protocol); + } + } + + if (!failedChecks.isEmpty()) { + String message = String.format( + "Protocol(s) should in the deprecated protocol list: %s. Current list: %s", + StringUtils.join(expectedProtocols, ','), protocolList); + fail(message); + } + } +} diff --git a/test/src/test/java/jenkins/install/SetupWizardTest.java b/test/src/test/java/jenkins/install/SetupWizardTest.java index 469b81661dfa..03dbc0df74f9 100644 --- a/test/src/test/java/jenkins/install/SetupWizardTest.java +++ b/test/src/test/java/jenkins/install/SetupWizardTest.java @@ -32,6 +32,9 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.util.Set; +import jenkins.AgentProtocolTest; +import jenkins.slaves.DeprecatedAgentProtocolMonitor; import org.apache.commons.io.FileUtils; import static org.hamcrest.Matchers.*; import org.junit.Before; @@ -39,6 +42,7 @@ import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertFalse; import org.junit.rules.TemporaryFolder; import org.jvnet.hudson.test.Issue; @@ -111,6 +115,17 @@ public void shouldProhibitAccessToPluginListWithoutAuth() throws Exception { wc.assertFails("setupWizard/completeInstall", 403); } + @Test + @Issue("JENKINS-45841") + public void shouldDisableUnencryptedProtocolsByDefault() throws Exception { + AgentProtocolTest.assertProtocols(j.jenkins, true, + "Encrypted JNLP4-protocols protocol should be enabled", "JNLP4-connect"); + AgentProtocolTest.assertProtocols(j.jenkins, false, + "Non-encrypted JNLP protocols should be disabled by default", + "JNLP-connect", "JNLP2-connect", "CLI-connect"); + AgentProtocolTest.assertMonitorNotActive(); + } + private String jsonRequest(JenkinsRule.WebClient wc, String path) throws Exception { // Try to call the actions method to retrieve the data final Page res; diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/config.xml b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/config.xml new file mode 100644 index 000000000000..e21f1873e8a4 --- /dev/null +++ b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/config.xml @@ -0,0 +1,42 @@ + + + + 1.0 + 2 + NORMAL + true + + + false + + ${ITEM_ROOTDIR}/workspace + ${ITEM_ROOTDIR}/builds + + + + + + 0 + + + + all + false + false + + + + all + 0 + + CLI-connect + CLI2-connect + JNLP3-connect + + + JNLP4-connect + + + + + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/jenkins.CLI.xml b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/jenkins.CLI.xml new file mode 100644 index 000000000000..7a9019446246 --- /dev/null +++ b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldDisableCLIProtocolsWhenCLIisDisabled/jenkins.CLI.xml @@ -0,0 +1,4 @@ + + + false + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml new file mode 100644 index 000000000000..16c467b8076a --- /dev/null +++ b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml @@ -0,0 +1,39 @@ + + + + 1.0 + 2 + NORMAL + true + + + false + + ${ITEM_ROOTDIR}/workspace + ${ITEM_ROOTDIR}/builds + + + + + + 0 + + + + all + false + false + + + + all + 0 + + + + + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotOverrideUserConfiguration/config.xml b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotOverrideUserConfiguration/config.xml new file mode 100644 index 000000000000..921c61d8908b --- /dev/null +++ b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotOverrideUserConfiguration/config.xml @@ -0,0 +1,45 @@ + + + + 1.0 + 2 + NORMAL + true + + + false + + ${ITEM_ROOTDIR}/workspace + ${ITEM_ROOTDIR}/builds + + + + + + 0 + + + + all + false + false + + + + all + 0 + + + CLI-connect + JNLP-connect + JNLP3-connect + + + JNLP4-connect + JNLP2-connect + CLI2-connect + + + + + \ No newline at end of file