mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Use testcontainers (#741)
* Replace abstract class IntegrationBaseSpec with composition through IntegrationTestUtil * Switch to testcontainers in integration tests It allows running different SSH servers with different configurations in tests, giving ability to cover more bugs, like mentioned in #733.
This commit is contained in:
43
build.gradle
43
build.gradle
@@ -1,7 +1,3 @@
|
|||||||
import java.text.SimpleDateFormat
|
|
||||||
import com.bmuschko.gradle.docker.tasks.container.*
|
|
||||||
import com.bmuschko.gradle.docker.tasks.image.*
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "groovy"
|
id "groovy"
|
||||||
@@ -60,7 +56,7 @@ dependencies {
|
|||||||
testRuntimeOnly "ch.qos.logback:logback-classic:1.2.6"
|
testRuntimeOnly "ch.qos.logback:logback-classic:1.2.6"
|
||||||
testImplementation 'org.glassfish.grizzly:grizzly-http-server:2.4.4'
|
testImplementation 'org.glassfish.grizzly:grizzly-http-server:2.4.4'
|
||||||
testImplementation 'org.apache.httpcomponents:httpclient:4.5.9'
|
testImplementation 'org.apache.httpcomponents:httpclient:4.5.9'
|
||||||
|
testImplementation 'org.testcontainers:testcontainers:1.16.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
license {
|
license {
|
||||||
@@ -276,48 +272,11 @@ jacocoTestReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
task buildItestImage(type: DockerBuildImage) {
|
|
||||||
inputDir = file('src/itest/docker-image')
|
|
||||||
images.add('sshj/sshd-itest:latest')
|
|
||||||
}
|
|
||||||
|
|
||||||
task createItestContainer(type: DockerCreateContainer) {
|
|
||||||
dependsOn buildItestImage
|
|
||||||
targetImageId buildItestImage.getImageId()
|
|
||||||
hostConfig.portBindings = ['2222:22']
|
|
||||||
hostConfig.autoRemove = true
|
|
||||||
}
|
|
||||||
|
|
||||||
task startItestContainer(type: DockerStartContainer) {
|
|
||||||
dependsOn createItestContainer
|
|
||||||
targetContainerId createItestContainer.getContainerId()
|
|
||||||
}
|
|
||||||
|
|
||||||
task logItestContainer(type: DockerLogsContainer) {
|
|
||||||
dependsOn createItestContainer
|
|
||||||
targetContainerId createItestContainer.getContainerId()
|
|
||||||
showTimestamps = true
|
|
||||||
stdErr = true
|
|
||||||
stdOut = true
|
|
||||||
tailAll = true
|
|
||||||
}
|
|
||||||
|
|
||||||
task stopItestContainer(type: DockerStopContainer) {
|
|
||||||
targetContainerId createItestContainer.getContainerId()
|
|
||||||
}
|
|
||||||
|
|
||||||
task forkedUploadRelease(type: GradleBuild) {
|
task forkedUploadRelease(type: GradleBuild) {
|
||||||
buildFile = project.buildFile
|
buildFile = project.buildFile
|
||||||
tasks = ["clean", "publishToSonatype", "closeAndReleaseSonatypeStagingRepository"]
|
tasks = ["clean", "publishToSonatype", "closeAndReleaseSonatypeStagingRepository"]
|
||||||
}
|
}
|
||||||
|
|
||||||
project.tasks.integrationTest.dependsOn(startItestContainer)
|
|
||||||
project.tasks.integrationTest.finalizedBy(stopItestContainer)
|
|
||||||
|
|
||||||
// Being enabled, it pollutes logs on CI. Uncomment when debugging some test to get sshd logs.
|
|
||||||
// project.tasks.stopItestContainer.dependsOn(logItestContainer)
|
|
||||||
|
|
||||||
project.tasks.release.dependsOn([project.tasks.integrationTest, project.tasks.build])
|
project.tasks.release.dependsOn([project.tasks.integrationTest, project.tasks.build])
|
||||||
project.tasks.release.finalizedBy(project.tasks.forkedUploadRelease)
|
project.tasks.release.finalizedBy(project.tasks.forkedUploadRelease)
|
||||||
project.tasks.jacocoTestReport.dependsOn(project.tasks.test)
|
project.tasks.jacocoTestReport.dependsOn(project.tasks.test)
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
FROM sickp/alpine-sshd:7.5-r2
|
|
||||||
|
|
||||||
ADD authorized_keys /home/sshj/.ssh/authorized_keys
|
|
||||||
|
|
||||||
ADD test-container/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key
|
|
||||||
ADD test-container/ssh_host_ecdsa_key.pub /etc/ssh/ssh_host_ecdsa_key.pub
|
|
||||||
ADD test-container/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key
|
|
||||||
ADD test-container/ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub
|
|
||||||
ADD test-container/sshd_config /etc/ssh/sshd_config
|
|
||||||
COPY test-container/trusted_ca_keys /etc/ssh/trusted_ca_keys
|
|
||||||
COPY test-container/host_keys/* /etc/ssh/
|
|
||||||
|
|
||||||
RUN apk add --no-cache tini
|
|
||||||
RUN \
|
|
||||||
echo "root:smile" | chpasswd && \
|
|
||||||
adduser -D -s /bin/ash sshj && \
|
|
||||||
passwd -u sshj && \
|
|
||||||
echo "sshj:ultrapassword" | chpasswd && \
|
|
||||||
chmod 600 /home/sshj/.ssh/authorized_keys && \
|
|
||||||
chmod 600 /etc/ssh/ssh_host_*_key && \
|
|
||||||
chmod 644 /etc/ssh/*.pub && \
|
|
||||||
chown -R sshj:sshj /home/sshj
|
|
||||||
|
|
||||||
ENTRYPOINT ["/sbin/tini", "/entrypoint.sh", "-o", "LogLevel=DEBUG2"]
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C)2009 - SSHJ Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.hierynomus.sshj
|
|
||||||
|
|
||||||
import net.schmizz.sshj.Config
|
|
||||||
import net.schmizz.sshj.DefaultConfig
|
|
||||||
import net.schmizz.sshj.SSHClient
|
|
||||||
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
|
|
||||||
import spock.lang.Specification
|
|
||||||
|
|
||||||
class IntegrationBaseSpec extends Specification {
|
|
||||||
protected static final int DOCKER_PORT = 2222
|
|
||||||
protected static final String USERNAME = "sshj"
|
|
||||||
protected static final String KEYFILE = "src/itest/resources/keyfiles/id_rsa"
|
|
||||||
protected final static String SERVER_IP = System.getProperty("serverIP", "127.0.0.1")
|
|
||||||
|
|
||||||
protected static SSHClient getConnectedClient(Config config) {
|
|
||||||
SSHClient sshClient = new SSHClient(config)
|
|
||||||
sshClient.addHostKeyVerifier(new PromiscuousVerifier())
|
|
||||||
sshClient.connect(SERVER_IP, DOCKER_PORT)
|
|
||||||
|
|
||||||
return sshClient
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static SSHClient getConnectedClient() throws IOException {
|
|
||||||
return getConnectedClient(new DefaultConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -20,9 +20,15 @@ import net.schmizz.sshj.DefaultConfig
|
|||||||
import net.schmizz.sshj.SSHClient
|
import net.schmizz.sshj.SSHClient
|
||||||
import net.schmizz.sshj.transport.TransportException
|
import net.schmizz.sshj.transport.TransportException
|
||||||
import net.schmizz.sshj.userauth.UserAuthException
|
import net.schmizz.sshj.userauth.UserAuthException
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class IntegrationSpec extends IntegrationBaseSpec {
|
class IntegrationSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should accept correct key for #signatureName"() {
|
def "should accept correct key for #signatureName"() {
|
||||||
@@ -33,7 +39,7 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
|||||||
sshClient.addHostKeyVerifier(fingerprint) // test-containers/ssh_host_ecdsa_key's fingerprint
|
sshClient.addHostKeyVerifier(fingerprint) // test-containers/ssh_host_ecdsa_key's fingerprint
|
||||||
|
|
||||||
when:
|
when:
|
||||||
sshClient.connect(SERVER_IP, DOCKER_PORT)
|
sshClient.connect(sshd.containerIpAddress, sshd.firstMappedPort)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
sshClient.isConnected()
|
sshClient.isConnected()
|
||||||
@@ -50,7 +56,7 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
|||||||
sshClient.addHostKeyVerifier("d4:6a:a9:52:05:ab:b5:48:dd:73:60:18:0c:3a:f0:a3")
|
sshClient.addHostKeyVerifier("d4:6a:a9:52:05:ab:b5:48:dd:73:60:18:0c:3a:f0:a3")
|
||||||
|
|
||||||
when:
|
when:
|
||||||
sshClient.connect(SERVER_IP, DOCKER_PORT)
|
sshClient.connect(sshd.containerIpAddress, sshd.firstMappedPort)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
thrown(TransportException.class)
|
thrown(TransportException.class)
|
||||||
@@ -59,11 +65,11 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
|||||||
@Unroll
|
@Unroll
|
||||||
def "should authenticate with key #key"() {
|
def "should authenticate with key #key"() {
|
||||||
given:
|
given:
|
||||||
SSHClient client = getConnectedClient()
|
SSHClient client = sshd.getConnectedClient()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def keyProvider = passphrase != null ? client.loadKeys("src/itest/resources/keyfiles/$key", passphrase) : client.loadKeys("src/itest/resources/keyfiles/$key")
|
def keyProvider = passphrase != null ? client.loadKeys("src/itest/resources/keyfiles/$key", passphrase) : client.loadKeys("src/itest/resources/keyfiles/$key")
|
||||||
client.authPublickey(USERNAME, keyProvider)
|
client.authPublickey(IntegrationTestUtil.USERNAME, keyProvider)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.isAuthenticated()
|
client.isAuthenticated()
|
||||||
@@ -83,7 +89,7 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
|||||||
|
|
||||||
def "should not authenticate with wrong key"() {
|
def "should not authenticate with wrong key"() {
|
||||||
given:
|
given:
|
||||||
SSHClient client = getConnectedClient()
|
SSHClient client = sshd.getConnectedClient()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey("sshj", "src/itest/resources/keyfiles/id_unknown_key")
|
client.authPublickey("sshj", "src/itest/resources/keyfiles/id_unknown_key")
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj
|
||||||
|
|
||||||
|
class IntegrationTestUtil {
|
||||||
|
static final String USERNAME = "sshj"
|
||||||
|
static final String KEYFILE = "src/itest/resources/keyfiles/id_rsa"
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj;
|
||||||
|
|
||||||
|
import org.testcontainers.containers.wait.strategy.WaitStrategy;
|
||||||
|
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wait strategy designed for {@link SshdContainer} to wait until the SSH server is ready, to avoid races when a test
|
||||||
|
* tries to connect to a server before the server has started.
|
||||||
|
*/
|
||||||
|
public class SshServerWaitStrategy implements WaitStrategy {
|
||||||
|
private Duration startupTimeout = Duration.ofMinutes(1);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void waitUntilReady(WaitStrategyTarget waitStrategyTarget) {
|
||||||
|
long expectedEnd = System.nanoTime() + startupTimeout.toNanos();
|
||||||
|
while (true) {
|
||||||
|
long attemptStart = System.nanoTime();
|
||||||
|
IOException error = null;
|
||||||
|
byte[] buffer = new byte[7];
|
||||||
|
try (Socket socket = new Socket()) {
|
||||||
|
socket.setSoTimeout(500);
|
||||||
|
socket.connect(new InetSocketAddress(
|
||||||
|
waitStrategyTarget.getHost(), waitStrategyTarget.getFirstMappedPort()));
|
||||||
|
// Haven't seen any SSH server that sends the version in two or more packets.
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
socket.getInputStream().read(buffer);
|
||||||
|
if (!Arrays.equals(buffer, "SSH-2.0".getBytes(StandardCharsets.UTF_8))) {
|
||||||
|
error = new IOException("The version message doesn't look like an SSH server version");
|
||||||
|
}
|
||||||
|
} catch (IOException err) {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == null) {
|
||||||
|
break;
|
||||||
|
} else if (System.nanoTime() >= expectedEnd) {
|
||||||
|
throw new RuntimeException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
//noinspection BusyWait
|
||||||
|
Thread.sleep(Math.max(0L, 500L - (System.nanoTime() - attemptStart) / 1_000_000));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WaitStrategy withStartupTimeout(Duration startupTimeout) {
|
||||||
|
this.startupTimeout = startupTimeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/itest/groovy/com/hierynomus/sshj/SshdContainer.java
Normal file
84
src/itest/groovy/com/hierynomus/sshj/SshdContainer.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.Config;
|
||||||
|
import net.schmizz.sshj.DefaultConfig;
|
||||||
|
import net.schmizz.sshj.SSHClient;
|
||||||
|
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
|
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JUnit4 rule for launching a generic SSH server container.
|
||||||
|
*/
|
||||||
|
public class SshdContainer extends GenericContainer<SshdContainer> {
|
||||||
|
@SuppressWarnings("unused") // Used dynamically by Spock
|
||||||
|
public SshdContainer() {
|
||||||
|
this(new ImageFromDockerfile()
|
||||||
|
.withDockerfileFromBuilder(SshdContainer::defaultDockerfileBuilder)
|
||||||
|
.withFileFromPath(".", Paths.get("src/itest/docker-image")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SshdContainer(@NotNull Future<String> future) {
|
||||||
|
super(future);
|
||||||
|
withExposedPorts(22);
|
||||||
|
setWaitStrategy(new SshServerWaitStrategy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void defaultDockerfileBuilder(@NotNull DockerfileBuilder builder) {
|
||||||
|
builder.from("sickp/alpine-sshd:7.5-r2");
|
||||||
|
|
||||||
|
builder.add("authorized_keys", "/home/sshj/.ssh/authorized_keys");
|
||||||
|
|
||||||
|
builder.add("test-container/ssh_host_ecdsa_key", "/etc/ssh/ssh_host_ecdsa_key");
|
||||||
|
builder.add("test-container/ssh_host_ecdsa_key.pub", "/etc/ssh/ssh_host_ecdsa_key.pub");
|
||||||
|
builder.add("test-container/ssh_host_ed25519_key", "/etc/ssh/ssh_host_ed25519_key");
|
||||||
|
builder.add("test-container/ssh_host_ed25519_key.pub", "/etc/ssh/ssh_host_ed25519_key.pub");
|
||||||
|
builder.add("test-container/sshd_config", "/etc/ssh/sshd_config");
|
||||||
|
builder.copy("test-container/trusted_ca_keys", "/etc/ssh/trusted_ca_keys");
|
||||||
|
builder.copy("test-container/host_keys/*", "/etc/ssh/");
|
||||||
|
|
||||||
|
builder.run("apk add --no-cache tini"
|
||||||
|
+ " && echo \"root:smile\" | chpasswd"
|
||||||
|
+ " && adduser -D -s /bin/ash sshj"
|
||||||
|
+ " && passwd -u sshj"
|
||||||
|
+ " && echo \"sshj:ultrapassword\" | chpasswd"
|
||||||
|
+ " && chmod 600 /home/sshj/.ssh/authorized_keys"
|
||||||
|
+ " && chmod 600 /etc/ssh/ssh_host_*_key"
|
||||||
|
+ " && chmod 644 /etc/ssh/*.pub"
|
||||||
|
+ " && chown -R sshj:sshj /home/sshj");
|
||||||
|
builder.entryPoint("/sbin/tini", "/entrypoint.sh", "-o", "LogLevel=DEBUG2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSHClient getConnectedClient(Config config) throws IOException {
|
||||||
|
SSHClient sshClient = new SSHClient(config);
|
||||||
|
sshClient.addHostKeyVerifier(new PromiscuousVerifier());
|
||||||
|
sshClient.connect("127.0.0.1", getFirstMappedPort());
|
||||||
|
|
||||||
|
return sshClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSHClient getConnectedClient() throws IOException {
|
||||||
|
return getConnectedClient(new DefaultConfig());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,21 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.sftp
|
package com.hierynomus.sshj.sftp
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import net.schmizz.sshj.SSHClient
|
import net.schmizz.sshj.SSHClient
|
||||||
import net.schmizz.sshj.sftp.OpenMode
|
import net.schmizz.sshj.sftp.OpenMode
|
||||||
import net.schmizz.sshj.sftp.RemoteFile
|
import net.schmizz.sshj.sftp.RemoteFile
|
||||||
import net.schmizz.sshj.sftp.SFTPClient
|
import net.schmizz.sshj.sftp.SFTPClient
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
import static org.codehaus.groovy.runtime.IOGroovyMethods.withCloseable
|
import static org.codehaus.groovy.runtime.IOGroovyMethods.withCloseable
|
||||||
|
|
||||||
class FileWriteSpec extends IntegrationBaseSpec {
|
class FileWriteSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
def "should append to file (GH issue #390)"() {
|
def "should append to file (GH issue #390)"() {
|
||||||
given:
|
given:
|
||||||
SSHClient client = getConnectedClient()
|
SSHClient client = sshd.getConnectedClient()
|
||||||
client.authPublickey("sshj", "src/test/resources/id_rsa")
|
client.authPublickey("sshj", "src/test/resources/id_rsa")
|
||||||
SFTPClient sftp = client.newSFTPClient()
|
SFTPClient sftp = client.newSFTPClient()
|
||||||
def file = "/home/sshj/test.txt"
|
def file = "/home/sshj/test.txt"
|
||||||
|
|||||||
@@ -15,10 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.signature
|
package com.hierynomus.sshj.signature
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import net.schmizz.sshj.DefaultConfig
|
||||||
import net.schmizz.sshj.SSHClient
|
import net.schmizz.sshj.SSHClient
|
||||||
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts
|
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts
|
||||||
|
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@@ -29,15 +33,20 @@ import java.util.stream.Collectors
|
|||||||
*
|
*
|
||||||
* Also, take a look at the unit test {@link net.schmizz.sshj.transport.verification.KeyWithCertificateUnitSpec}.
|
* Also, take a look at the unit test {@link net.schmizz.sshj.transport.verification.KeyWithCertificateUnitSpec}.
|
||||||
*/
|
*/
|
||||||
class KeyWithCertificateSpec extends IntegrationBaseSpec {
|
class KeyWithCertificateSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "authorising with a signed public key #keyName"() {
|
def "authorising with a signed public key #keyName"() {
|
||||||
given:
|
given:
|
||||||
def client = getConnectedClient()
|
SSHClient client = new SSHClient(new DefaultConfig())
|
||||||
|
client.addHostKeyVerifier(new PromiscuousVerifier())
|
||||||
|
client.connect("127.0.0.1", sshd.firstMappedPort)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, "src/itest/resources/keyfiles/certificates/$keyName")
|
client.authPublickey("sshj", "src/itest/resources/keyfiles/certificates/$keyName")
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
@@ -82,9 +91,10 @@ class KeyWithCertificateSpec extends IntegrationBaseSpec {
|
|||||||
|
|
||||||
and:
|
and:
|
||||||
File caPubKey = new File("src/itest/resources/keyfiles/certificates/CA_rsa.pem.pub")
|
File caPubKey = new File("src/itest/resources/keyfiles/certificates/CA_rsa.pem.pub")
|
||||||
|
def address = "127.0.0.1"
|
||||||
String knownHostsFileContents = "" +
|
String knownHostsFileContents = "" +
|
||||||
"@cert-authority $SERVER_IP ${caPubKey.text}" +
|
"@cert-authority ${ address} ${caPubKey.text}" +
|
||||||
"\n@cert-authority [$SERVER_IP]:$DOCKER_PORT ${caPubKey.text}"
|
"\n@cert-authority [${address}]:${sshd.firstMappedPort} ${caPubKey.text}"
|
||||||
knownHosts.write(knownHostsFileContents)
|
knownHosts.write(knownHostsFileContents)
|
||||||
|
|
||||||
and:
|
and:
|
||||||
@@ -94,7 +104,7 @@ class KeyWithCertificateSpec extends IntegrationBaseSpec {
|
|||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
SSHClient sshClient = new SSHClient(config)
|
SSHClient sshClient = new SSHClient(config)
|
||||||
sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(knownHosts))
|
sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(knownHosts))
|
||||||
sshClient.connect(SERVER_IP, DOCKER_PORT)
|
sshClient.connect(address, sshd.firstMappedPort)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
sshClient.authPassword("sshj", "ultrapassword")
|
sshClient.authPassword("sshj", "ultrapassword")
|
||||||
|
|||||||
@@ -15,18 +15,25 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.signature
|
package com.hierynomus.sshj.signature
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import com.hierynomus.sshj.SshdContainer
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class RsaSignatureClientKeySpec extends IntegrationBaseSpec {
|
class RsaSignatureClientKeySpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should correctly connect using publickey auth with RSA key with signature"() {
|
def "should correctly connect using publickey auth with RSA key with signature"() {
|
||||||
given:
|
given:
|
||||||
def client = getConnectedClient(new DefaultConfig())
|
def client = sshd.getConnectedClient()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, "src/itest/resources/keyfiles/id_rsa2")
|
client.authPublickey(IntegrationTestUtil.USERNAME, "src/itest/resources/keyfiles/id_rsa2")
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
|
|||||||
@@ -15,22 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.signature
|
package com.hierynomus.sshj.signature
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import com.hierynomus.sshj.key.KeyAlgorithms
|
import com.hierynomus.sshj.key.KeyAlgorithms
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import net.schmizz.sshj.DefaultConfig
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class SignatureSpec extends IntegrationBaseSpec {
|
class SignatureSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should correctly connect with #sig Signature"() {
|
def "should correctly connect with #sig Signature"() {
|
||||||
given:
|
given:
|
||||||
def cfg = new DefaultConfig()
|
def cfg = new DefaultConfig()
|
||||||
cfg.setKeyAlgorithms(Collections.singletonList(sigFactory))
|
cfg.setKeyAlgorithms(Collections.singletonList(sigFactory))
|
||||||
def client = getConnectedClient(cfg)
|
def client = sshd.getConnectedClient(cfg)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, KEYFILE)
|
client.authPublickey(IntegrationTestUtil.USERNAME, IntegrationTestUtil.KEYFILE)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
|
|||||||
@@ -15,21 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.transport.cipher
|
package com.hierynomus.sshj.transport.cipher
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import net.schmizz.sshj.DefaultConfig
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class CipherSpec extends IntegrationBaseSpec {
|
class CipherSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should correctly connect with #cipher Cipher"() {
|
def "should correctly connect with #cipher Cipher"() {
|
||||||
given:
|
given:
|
||||||
def cfg = new DefaultConfig()
|
def cfg = new DefaultConfig()
|
||||||
cfg.setCipherFactories(cipherFactory)
|
cfg.setCipherFactories(cipherFactory)
|
||||||
def client = getConnectedClient(cfg)
|
def client = sshd.getConnectedClient(cfg)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, KEYFILE)
|
client.authPublickey(IntegrationTestUtil.USERNAME, IntegrationTestUtil.KEYFILE)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
|
|||||||
@@ -15,29 +15,32 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.transport.kex
|
package com.hierynomus.sshj.transport.kex
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
import com.hierynomus.sshj.transport.mac.Macs
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import net.schmizz.sshj.DefaultConfig
|
||||||
import net.schmizz.sshj.transport.kex.Curve25519DH
|
|
||||||
import net.schmizz.sshj.transport.kex.Curve25519SHA256
|
import net.schmizz.sshj.transport.kex.Curve25519SHA256
|
||||||
import net.schmizz.sshj.transport.kex.DH
|
|
||||||
import net.schmizz.sshj.transport.kex.DHGexSHA1
|
import net.schmizz.sshj.transport.kex.DHGexSHA1
|
||||||
import net.schmizz.sshj.transport.kex.DHGexSHA256
|
import net.schmizz.sshj.transport.kex.DHGexSHA256
|
||||||
import net.schmizz.sshj.transport.kex.ECDH
|
|
||||||
import net.schmizz.sshj.transport.kex.ECDHNistP
|
import net.schmizz.sshj.transport.kex.ECDHNistP
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class KexSpec extends IntegrationBaseSpec {
|
class KexSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should correctly connect with #kex Key Exchange"() {
|
def "should correctly connect with #kex Key Exchange"() {
|
||||||
given:
|
given:
|
||||||
def cfg = new DefaultConfig()
|
def cfg = new DefaultConfig()
|
||||||
cfg.setKeyExchangeFactories(kexFactory)
|
cfg.setKeyExchangeFactories(kexFactory)
|
||||||
def client = getConnectedClient(cfg)
|
def client = sshd.getConnectedClient(cfg)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, KEYFILE)
|
client.authPublickey(IntegrationTestUtil.USERNAME, IntegrationTestUtil.KEYFILE)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
|
|||||||
@@ -15,21 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj.transport.mac
|
package com.hierynomus.sshj.transport.mac
|
||||||
|
|
||||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
import com.hierynomus.sshj.IntegrationTestUtil
|
||||||
|
import com.hierynomus.sshj.SshdContainer
|
||||||
import net.schmizz.sshj.DefaultConfig
|
import net.schmizz.sshj.DefaultConfig
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class MacSpec extends IntegrationBaseSpec {
|
class MacSpec extends Specification {
|
||||||
|
@Shared
|
||||||
|
@ClassRule
|
||||||
|
SshdContainer sshd
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
def "should correctly connect with #mac MAC"() {
|
def "should correctly connect with #mac MAC"() {
|
||||||
given:
|
given:
|
||||||
def cfg = new DefaultConfig()
|
def cfg = new DefaultConfig()
|
||||||
cfg.setMACFactories(macFactory)
|
cfg.setMACFactories(macFactory)
|
||||||
def client = getConnectedClient(cfg)
|
def client = sshd.getConnectedClient(cfg)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, KEYFILE)
|
client.authPublickey(IntegrationTestUtil.USERNAME, IntegrationTestUtil.KEYFILE)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
@@ -47,10 +54,10 @@ class MacSpec extends IntegrationBaseSpec {
|
|||||||
given:
|
given:
|
||||||
def cfg = new DefaultConfig()
|
def cfg = new DefaultConfig()
|
||||||
cfg.setMACFactories(macFactory)
|
cfg.setMACFactories(macFactory)
|
||||||
def client = getConnectedClient(cfg)
|
def client = sshd.getConnectedClient(cfg)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
client.authPublickey(USERNAME, KEYFILE)
|
client.authPublickey(IntegrationTestUtil.USERNAME, IntegrationTestUtil.KEYFILE)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
client.authenticated
|
client.authenticated
|
||||||
|
|||||||
Reference in New Issue
Block a user