Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d2ed8f5
Bump plugin from 4.37 to 4.38 (#61)
dependabot[bot] Mar 21, 2022
6d70122
Remove some deprecated API calls (#57)
offa Apr 5, 2022
251d590
Bump sshd-core from 2.7.0 to 2.8.0 (#55)
dependabot[bot] Apr 6, 2022
ded912b
feat: enable continuous delivery workflow (#65)
kuisathaverat Apr 10, 2022
7b40a4d
Bump slf4j.version from 1.7.32 to 1.7.36 (#64)
dependabot[bot] Apr 10, 2022
935ee52
Bump actions/checkout from 2.3.4 to 3.0.0 (#66)
dependabot[bot] Apr 10, 2022
b1769a7
Bump actions/setup-java from 2 to 3 (#67)
dependabot[bot] Apr 10, 2022
9c29c7a
Bump plugin from 4.38 to 4.40 (#63)
dependabot[bot] Apr 10, 2022
4c9f9e6
Stop bundling SLF4J (#68)
basil Apr 12, 2022
aa9199e
Bump actions/checkout from 3.0.0 to 3.0.1 (#69)
dependabot[bot] Apr 15, 2022
2451ae1
Bump actions/checkout from 3.0.1 to 3.0.2
dependabot[bot] Apr 22, 2022
ad10c28
Use Eclipse Temurin for action, not AdoptOpenJDK (#71)
MarkEWaite Apr 22, 2022
3da6b08
Merge pull request #70 from jenkinsci/dependabot/github_actions/actio…
MarkEWaite Apr 22, 2022
7e112e5
Bump jenkins-infra/jenkins-maven-cd-action from 1.2.0 to 1.3.0 (#72)
dependabot[bot] May 6, 2022
8470b24
Bump jenkins-infra/interesting-category-action from 1.0.0 to 1.1.0 (#73)
dependabot[bot] May 10, 2022
2ee6961
Do not bundle a copy of `instance-identity`
jglick May 19, 2022
ed5e1bc
Merge pull request #75 from jglick/instance-identity
jglick May 19, 2022
883d165
[JENKINS-68541] Prevent stdout/stderr stream from being closed by inv…
Dohbedoh May 20, 2022
e396060
Bump jenkins-infra/jenkins-maven-cd-action from 1.3.0 to 1.3.1 (#78)
dependabot[bot] Jun 14, 2022
2a53a1d
Bump jenkins-infra/interesting-category-action from 1.1.0 to 1.2.0 (#77)
dependabot[bot] Jun 14, 2022
b0a8ed0
Bump jenkins-infra/verify-ci-status-action from 1.2.0 to 1.2.1 (#76)
dependabot[bot] Jun 14, 2022
717dd36
chore: use jenkins infra maven cd reusable workflow (#79)
jetersen Jun 15, 2022
adb9dab
Bundle mina-sshd-api-core plugin instead of sshd-core (#80)
Dohbedoh Jun 20, 2022
aaebba7
chore(deps): bump plugin from 4.40 to 4.41
dependabot[bot] Jun 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
interval: "weekly"
- package-ecosystem: "github-actions"
directory: /
schedule:
interval: "daily"
2 changes: 0 additions & 2 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
_extends: .github
name-template: v$NEXT_MINOR_VERSION 🌈
tag-template: sshd-$NEXT_MINOR_VERSION

15 changes: 15 additions & 0 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins

name: cd
on:
workflow_dispatch:
check_run:
types:
- completed

jobs:
maven-cd:
uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1
secrets:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
19 changes: 0 additions & 19 deletions .github/workflows/changelog.yml

This file was deleted.

1 change: 1 addition & 0 deletions .mvn/maven.config
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
-Pconsume-incrementals
-Pmight-produce-incrementals
-Dchangelist.format=%d.v%s
29 changes: 8 additions & 21 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>4.37</version>
<version>4.41</version>
<relativePath />
</parent>

<groupId>org.jenkins-ci.modules</groupId> <!-- we use the modules groupId for historical reasons -->
<artifactId>sshd</artifactId>
<version>${revision}${changelist}</version>
<version>${revision}.${changelist}</version>
<packaging>hpi</packaging>
<name>SSH server</name>
<description>Adds SSH server functionality to Jenkins, exposing CLI commands through it</description>
Expand All @@ -29,29 +29,16 @@
</licenses>

<properties>
<revision>3.1.1</revision>
<changelist>-SNAPSHOT</changelist>
<revision>3</revision>
<changelist>999999-SNAPSHOT</changelist>
<jenkins.version>2.289.1</jenkins.version>
<java.level>8</java.level>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.277.x</artifactId>
<version>961.vf0c9f6f59827</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.7.0</version>
<groupId>io.jenkins.plugins.mina-sshd-api</groupId>
<artifactId>mina-sshd-api-core</artifactId>
<version>2.8.0-18.vd98674ecd652</version>
</dependency>
<dependency>
<groupId>net.i2p.crypto</groupId>
Expand All @@ -61,7 +48,7 @@
<dependency>
<groupId>org.jenkins-ci.modules</groupId>
<artifactId>instance-identity</artifactId>
<version>2.2</version> <!-- We use the module for the moment -->
<scope>provided</scope> <!-- TODO pending JEP-230 we use the module -->
</dependency>
<dependency>
<groupId>org.jenkins-ci</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ public void setSession(ServerSession session) {

@CheckForNull
protected User getCurrentUser() {
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins != null && jenkins.isUseSecurity()) {
return User.get(getSession().getUsername()); // then UserAuthNamedFactory must have done public key auth
final Jenkins jenkins = Jenkins.get();
if (jenkins.isUseSecurity()) {
return User.getById(getSession().getUsername(), true); // then UserAuthNamedFactory must have done public key auth
} else {
return null; // not authenticated. anonymous.
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.jenkinsci.main.modules.sshd;

import hudson.CloseProofOutputStream;
import hudson.Extension;
import hudson.cli.CLICommand;
import hudson.model.User;
import org.apache.sshd.server.command.Command;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.util.Locale;
import org.apache.sshd.server.command.Command;

/**
* {@link SshCommandFactory} that invokes {@link CLICommand}s.
Expand All @@ -26,14 +28,17 @@ public Command create(CommandLine commandLine) {
@Override
public int runCommand() throws IOException {
User u = getCurrentUser();
if (u!=null) c.setTransportAuth(u.impersonate());
if (u != null) {
c.setTransportAuth2(u.impersonate2());
}

CommandLine cmds = getCmdLine();

//TODO: Consider switching to UTF-8
//TODO: Consider removing the CloseProofOutputStream wrapper when SSHD-1257 is available
return c.main(cmds.subList(1,cmds.size()), Locale.getDefault(), getInputStream(),
new PrintStream(getOutputStream(), false, Charset.defaultCharset().toString()),
new PrintStream(getErrorStream(), false, Charset.defaultCharset().toString()));
new PrintStream(new CloseProofOutputStream(getOutputStream()), false, Charset.defaultCharset().toString()),
new PrintStream(new CloseProofOutputStream(getErrorStream()), false, Charset.defaultCharset().toString()));
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ public String getEndpoint() {
try {
int p = sshd.getActualPort();
if (p>0) {
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
throw new IllegalStateException("Jenkins has not been started, or was already shut down");
}
final Jenkins jenkins = Jenkins.get();
return (host != null ? host : new URL(jenkins.getRootUrl()).getHost()) + ":" + p;
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class UserAuthNamedFactory implements UserAuthFactory {
UserAuthFactory none = UserAuthNoneFactory.INSTANCE;

private UserAuthFactory select() {
final Jenkins jenkins = Jenkins.getInstance();
return (jenkins != null && jenkins.isUseSecurity()) ? publicKey : none;
final Jenkins jenkins = Jenkins.get();
return jenkins.isUseSecurity() ? publicKey : none;
}

public String getName() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/index.jelly
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?jelly escape-by-default='true'?>
<div>Adds SSH server functionality to Jenkins, exposing CLI commands through it.</div>
59 changes: 50 additions & 9 deletions src/test/java/org/jenkinsci/main/modules/cli/auth/ssh/CLITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@
package org.jenkinsci.main.modules.cli.auth.ssh;

import com.gargoylesoftware.htmlunit.WebResponse;
import hudson.Extension;
import hudson.Launcher;
import hudson.Proc;
import hudson.cli.CLICommand;
import hudson.model.FreeStyleProject;
import hudson.model.UnprotectedRootAction;
import hudson.model.User;
import hudson.security.csrf.CrumbExclusion;
import hudson.util.StreamTaskListener;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import io.jenkins.cli.shaded.org.apache.commons.io.FileUtils;
import io.jenkins.cli.shaded.org.apache.commons.io.output.TeeOutputStream;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import org.apache.commons.io.IOUtils;
import org.apache.sshd.common.util.io.ModifiableFileWatcher;
import org.jenkinsci.main.modules.sshd.SSHD;
Expand Down Expand Up @@ -64,17 +66,19 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeThat;
import static org.junit.Assume.assumeTrue;
Expand Down Expand Up @@ -130,7 +134,7 @@ public void strictHostKey() throws Exception {
SSHD.get().setPort(0);
File privkey = tmp.newFile("id_rsa");
FileUtils.copyURLToFile(CLITest.class.getResource("id_rsa"), privkey);
User.get("admin").addProperty(new UserPropertyImpl(IOUtils.toString(CLITest.class.getResource("id_rsa.pub"))));
User.getById("admin", true).addProperty(new UserPropertyImpl(IOUtils.toString(CLITest.class.getResource("id_rsa.pub"), StandardCharsets.UTF_8)));
assertNotEquals(0, new Launcher.LocalLauncher(StreamTaskListener.fromStderr()).launch().cmds(
"java", "-Duser.home=" + home, "-jar", jar.getAbsolutePath(), "-s", r.getURL().toString(), "-ssh", "-user", "admin", "-i", privkey.getAbsolutePath(), "-strictHostKey", "who-am-i"
).stdout(System.out).stderr(System.err).join());
Expand Down Expand Up @@ -162,7 +166,7 @@ public void interrupt() throws Exception {
SSHD.get().setPort(0);
File privkey = tmp.newFile("id_rsa");
FileUtils.copyURLToFile(CLITest.class.getResource("id_rsa"), privkey);
User.get("admin").addProperty(new UserPropertyImpl(IOUtils.toString(CLITest.class.getResource("id_rsa.pub"))));
User.getById("admin", true).addProperty(new UserPropertyImpl(IOUtils.toString(CLITest.class.getResource("id_rsa.pub"), StandardCharsets.UTF_8)));
FreeStyleProject p = r.createFreeStyleProject("p");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
p.getBuildersList().add(new SleepBuilder(TimeUnit.MINUTES.toMillis(2)));
Expand All @@ -179,6 +183,28 @@ public void interrupt() throws Exception {
r.waitForCompletion(p.getLastBuild());
}

@Issue("JENKINS-68541")
@Test
public void outputStream() throws Exception {
home = tempHome();
grabCliJar();

r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin"));
SSHD.get().setPort(0);
File privkey = tmp.newFile("id_rsa");
FileUtils.copyURLToFile(CLITest.class.getResource("id_rsa"), privkey);
User.getById("admin", true).addProperty(new UserPropertyImpl(IOUtils.toString(CLITest.class.getResource("id_rsa.pub"), StandardCharsets.UTF_8)));
StreamTaskListener stl = StreamTaskListener.fromStderr();
List<String> args = Arrays.asList("java", "-Duser.home=" + home, "-jar", jar.getAbsolutePath(), "-s", r.getURL().toString(), "-ssh", "-user", "admin", "-i", privkey.getAbsolutePath(), "close-stdout-stream");
int ret = new Launcher.LocalLauncher(stl).launch().cmds(args)
.stdout(System.out)
.stderr(System.err)
.start()
.joinWithTimeout(5, TimeUnit.SECONDS, stl);
assertEquals(0, ret);
}

@Test @Issue("JENKINS-44361")
public void reportNotJenkins() throws Exception {
home = tempHome();
Expand Down Expand Up @@ -241,9 +267,9 @@ public void redirectToEndpointShouldBeFollowed() throws Exception {

WebResponse rsp = wc.goTo("cli-proxy/").getWebResponse();
assertEquals(rsp.getContentAsString(), HttpURLConnection.HTTP_MOVED_TEMP, rsp.getStatusCode());
assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-Jenkins"));
assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-Jenkins-CLI-Port"));
assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-SSH-Endpoint"));
assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-Jenkins"));
assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-Jenkins-CLI-Port"));
assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-SSH-Endpoint"));

String url = r.getURL().toString() + "cli-proxy/";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Expand Down Expand Up @@ -296,4 +322,19 @@ public boolean process(HttpServletRequest request, HttpServletResponse response,
return true;
}
}

@Extension
public static class CloseStdoutStreamCommand extends CLICommand {

@Override
public String getShortDescription() {
return "Close stdout";
}

@Override
protected int run() {
stdout.close();
return 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void dsa() throws Exception {

private void testRoundtrip(String publicKey) throws Exception {
r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
User foo = User.get("foo");
User foo = User.getById("foo", true);
foo.addProperty(new UserPropertyImpl(publicKey));
r.configRoundtrip(foo);
assertEquals(publicKey, foo.getProperty(UserPropertyImpl.class).authorizedKeys);
Expand Down