Browse Source

Add more ssh tests: pushing, known_host file handling, etc.

Add support for git-receive-pack to the ssh git server and add two
new tests for pushing.

This actually uncovered an undocumented requirement in TransportSftp:
the FTP rename operation assumes POSIX semantics, i.e., that the
target is removed. This works as written only for servers that
support and advertise the "posix-rename@openssh.com" FTP extension.

Our little Apache MINA server does not advertise this extension.

Fix the FtpChannel implementation for Jsch to handle this case in a
meaningful way so that it can pass the new "push over sftp" test.

Add more tests to test the behavior of server host key checking.

Also refactor the tests generally to separate better the test
framework from the actual tests.

Bug: 520927
Change-Id: Ia4bb85e17ddacde7b36ee8c2d5d454bbfa66dfc3
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
stable-5.2
Thomas Wolf 6 years ago committed by Matthias Sohn
parent
commit
0173b25415
  1. 45
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
  2. 3
      org.eclipse.jgit.test/BUILD
  3. 15
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/id_dsa_test
  4. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/id_dsa_test.pub
  5. 12
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa
  6. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub
  7. 15
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass
  8. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub
  9. 5
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256
  10. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub
  11. 8
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass
  12. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub
  13. 6
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384
  14. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub
  15. 9
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass
  16. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub
  17. 7
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521
  18. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub
  19. 10
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass
  20. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub
  21. 7
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519
  22. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub
  23. 8
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass
  24. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub
  25. 15
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024
  26. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub
  27. 18
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass
  28. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub
  29. 27
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048
  30. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub
  31. 30
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass
  32. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub
  33. 39
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072
  34. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub
  35. 42
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass
  36. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub
  37. 51
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096
  38. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub
  39. 54
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass
  40. 1
      org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub
  41. 4
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JSchSshTest.java
  42. 608
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java
  43. 386
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java
  44. 30
      org.eclipse.jgit/src/org/eclipse/jgit/transport/FtpChannel.java
  45. 27
      org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
  46. 7
      org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java

45
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java

@ -53,8 +53,9 @@ import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.sshd.common.config.keys.IdentityUtils;
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.Session;
@ -65,13 +66,15 @@ import org.apache.sshd.server.shell.UnknownCommand;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.UploadPack;
/**
* A simple ssh/sftp git <em>test</em> server based on Apache MINA sshd.
* <p>
* Supports only a single repository. Authenticates only the given test user
* against his given test public key. ssh is limited to fetching (upload-pack).
* against his given test public key. Supports fetch and push.
* </p>
*
* @since 5.2
@ -112,9 +115,7 @@ public class SshTestGitServer {
@NonNull Repository repository, @NonNull byte[] hostKey)
throws IOException, GeneralSecurityException {
this.testUser = testUser;
this.testKey = IdentityUtils
.loadIdentities(Collections.singletonMap("A", testKey), null)
.get("A").getPublic();
setTestUserPublicKey(testKey);
this.repository = repository;
server = SshServer.setUpDefaultServer();
// Set host key
@ -156,9 +157,10 @@ public class SshTestGitServer {
.compareKeys(SshTestGitServer.this.testKey, publicKey);
});
server.setCommandFactory(command -> {
if (command.startsWith("git-upload-pack")
|| command.startsWith("git upload-pack")) {
if (command.startsWith(RemoteConfig.DEFAULT_UPLOAD_PACK)) {
return new GitUploadPackCommand(command, executorService);
} else if (command.startsWith(RemoteConfig.DEFAULT_RECEIVE_PACK)) {
return new GitReceivePackCommand(command, executorService);
}
return new UnknownCommand(command);
});
@ -186,6 +188,12 @@ public class SshTestGitServer {
server.stop(true);
}
public void setTestUserPublicKey(Path key)
throws IOException, GeneralSecurityException {
this.testKey = AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
.resolvePublicKey(PublicKeyEntryResolver.IGNORING);
}
private class GitUploadPackCommand extends AbstractCommandSupport {
protected GitUploadPackCommand(String command,
@ -214,4 +222,27 @@ public class SshTestGitServer {
}
}
private class GitReceivePackCommand extends AbstractCommandSupport {
protected GitReceivePackCommand(String command,
ExecutorService executorService) {
super(command, executorService, false);
}
@Override
public void run() {
try {
new ReceivePack(repository).receive(getInputStream(),
getOutputStream(), getErrorStream());
onExit(0);
} catch (IOException e) {
log.warn(
MessageFormat.format("Could not run {0}", getCommand()),
e);
onExit(-1, e.toString());
}
}
}
}

3
org.eclipse.jgit.test/BUILD

@ -20,7 +20,8 @@ HELPERS = glob(["src/**/*.java"]) + [PKG + c for c in [
"revwalk/RevWalkTestCase.java",
"transport/ObjectIdMatcher.java",
"transport/SpiTransport.java",
"transport/SshTestBase.java",
"transport/ssh/SshTestBase.java",
"transport/ssh/SshTestHarness.java",
"treewalk/FileTreeIteratorWithTimeControl.java",
"treewalk/filter/AlwaysCloneTreeFilter.java",
"test/resources/SampleDataRepositoryTestCase.java",

15
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/id_dsa_test

@ -1,15 +0,0 @@
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,D7B8FC3F4E304A2A22754B068767081F
IewkLt6JyqtPccAsnfeLv7IMlLvgm7tqQSYK1/CLhmDE0aZXViD8sqxLA6dVjmkp
BVyk7EBpp43PnVQYsDcMPnyM8H83vNRDtIQ6fxM1PJafiP7Rbn1k1fDh7DwA48PU
FnT6zZ9aYEKYMto0WIdQ86j/uY+LtYygQDDoZ2ohn2NlpykeyrSp0bDRIoW6sdc5
+LlfDtq2usv3fcxMAJpO/SSN78LvBlyOK4n/JAVSkPawsW1WsIrXA52mk0iUhjYc
aYOCuL+wA7OmHAOpfS5HUXZ4i/7qONnLBkEqeIOcgTmShh1c4oWw9TjWK1AzdSDU
G2nkRJ/8zK/jdm5wcmrjrzuREM1VbCiXHlVoHYI0W1Z9etOgz1cj4KLz/bB8Nf+8
shCez1Aw5ec33BzwysfwymfAKeXjYaxdKcur3j+UdXAlYRD28BRnWmTL5Jx82eUu
NIh0U9pHkn+PjdzmjSPEUP7wzDjQQacaQTkBRf5gPyOYfv/+Mnq6YyflKaPYmkEr
eztO22VZlpyp/hj2LzBav9wi0++teInNQGU+GxHedsWm4+YpffMhz1bz5ZUQ670A
0WJJH3k/KnxbCY3usj4eJr+CsX+LNZhm+rKyjRDmRwA=
-----END DSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/id_dsa_test.pub

@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAIsXi0EUiI6GmhHqrwwjvO2wdujW46+uXM/SG2GVI3KxCSf95B2XgXBsgiKH0sy3guyqjDcP4Ph5Mctg1IxqmqugN6xf9YB6lf09bRdIbumVGU6nXW7bZDHdk9nmvWy56vurofwvhoRnQBUJ3L4n7dxxvXhIyRPOxptayOS2ZcnRAAAAFQDsgGxVxcBBM9y0Rm3kNz/R64CYEQAAAIEAgCbyCJNZb66KQBMO7B+NPxx0caSKjZ+3TpWL6pLJGTAu1pztd1wpElECNCEBhTX9p1HEypTIjOUFU2gjgaBLUcWE0JK+/4vJjjvaENvrQardH0EeRfrazhpRY+X6ytUTk0YPDuQn+ZqBhXxAoD8BA+TJMvk7oMpMUTyr6LGBuj4AAACAeXCfOrKY6wHuMkHHpa9Ix95T+7h5ZrSosrV1WO5g9X04LNiPFRXvGyMWYF17VaGqVWID5NbbGP4PqwSw0rjmw7c/xxV2DYNfJ5NFWsDHxhI6RP9AaGTKcdIEykWEkGgJDiVF/DJgjvapGCW4Lo5UB1JJRXEM4YmTiEbyUyahKqw= thomas@Arcturus

12
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa

@ -0,0 +1,12 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQC+mJEX/XBloWhNM+BEuoh5z+EAuZfVyJ8cHNKlQmC1sWrENKGh
P8ZhzWeHW0A7JnvTQgMqW6yD4mDzCpbR1wEz5KeXAphEjCGPnRik7Q4RjpZTd6Nq
nNF/CYYGYuwR7ZGUPITTpKJWgX6NkEk+a4tvTWP7xfxOq5iKIspFEhEOlQIVAIBi
TdAR8M2twrXZdspBjdJprjDXAoGAOrRYdXRHhpsOewIi9GQah0lde7AVrmZawK9Z
BwhDUagL58gS8PvcsNNVhS2dKEX45pqZmgayt2UEE/5bke3+CdZtStDsezBYMu8P
I/0qjOULhl7xLJT5ayCIN2ZuvcH8vtqH89fXgZkIz0c68AzY1ZFjJPc+TdE0puI9
3mMVRaoCgYEAslyMZiOwYA3oiFMQTJEphKdgejWsjqQ9LoKppfZ3d4Jj1V3tgI1s
/wHfoneUUrUwM+sMHZKXbBDLWWQUOSIxDYcXKDkbZ1FlmhvJR+45D2LyLKjEnjVD
lQCwYly4P26zXqciZS7k3H/DjiHtAPUeoHm9IYb1A03K8Bd/xW0guMcCFFeUfQeX
3mFPCfKJ5uXMjkPUqIo/
-----END DSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub

@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAL6YkRf9cGWhaE0z4ES6iHnP4QC5l9XInxwc0qVCYLWxasQ0oaE/xmHNZ4dbQDsme9NCAypbrIPiYPMKltHXATPkp5cCmESMIY+dGKTtDhGOllN3o2qc0X8JhgZi7BHtkZQ8hNOkolaBfo2QST5ri29NY/vF/E6rmIoiykUSEQ6VAAAAFQCAYk3QEfDNrcK12XbKQY3Saa4w1wAAAIA6tFh1dEeGmw57AiL0ZBqHSV17sBWuZlrAr1kHCENRqAvnyBLw+9yw01WFLZ0oRfjmmpmaBrK3ZQQT/luR7f4J1m1K0Ox7MFgy7w8j/SqM5QuGXvEslPlrIIg3Zm69wfy+2ofz19eBmQjPRzrwDNjVkWMk9z5N0TSm4j3eYxVFqgAAAIEAslyMZiOwYA3oiFMQTJEphKdgejWsjqQ9LoKppfZ3d4Jj1V3tgI1s/wHfoneUUrUwM+sMHZKXbBDLWWQUOSIxDYcXKDkbZ1FlmhvJR+45D2LyLKjEnjVDlQCwYly4P26zXqciZS7k3H/DjiHtAPUeoHm9IYb1A03K8Bd/xW0guMc= testuser

15
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass

@ -0,0 +1,15 @@
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,EBB6ACAA4F1FC558865344E3C2B91A5F
CWMAq20YBO8ueHnmQ7IaKa7ISEvNbwbzqoBIxor6TZYSU3JvlIf5AL2UvGpMJDk1
fyROdCjdVAeWKQC0peU54D3YnD3am4gZlrclPMjMRnjBmqO+vnU7bTudIt/8y6vg
gmHZki0/aceQ6QvGwGrxBezBPaK4Bc926lePujHHE/PbtuQgkBw7rhIBGKVuy0qN
sFbC4AGnYl5tudy5RLvCcpQvpDCjnYAfGQVimRYSOsaOwTEBvsnQFUH1pqQAYLC4
Capo1yj6Q0smzwsGoyFSvmPkyzLbMTT42m+M48gc5nuaOkbU5absqOb8cQgRVmWB
W1HnpufqGtyF6vBK+qlzg157bhQDYMwZuubX+IrTRL67djBiSIpiRDZduJavT3zq
iSrRGSnjnkhp4NxtJJjprDQe4VAZEccN5GWPjClbogjpsG+fmTJiNDMI88L11DrV
Vjeaxsql31iur/xGwvmBYd+/V+Nu4v7kA4XViO/3ZIpqi8qvQ3si5hbALSX0OPnm
9q0eMp9qfmzPvbmysq2BEenBaZDwEWYTYpcF23pjwc1EvmfP8EAYT+xH95ZhxVmc
Sujq0VyGeIhy7+gRHZo2Fg==
-----END DSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub

@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAL6YkRf9cGWhaE0z4ES6iHnP4QC5l9XInxwc0qVCYLWxasQ0oaE/xmHNZ4dbQDsme9NCAypbrIPiYPMKltHXATPkp5cCmESMIY+dGKTtDhGOllN3o2qc0X8JhgZi7BHtkZQ8hNOkolaBfo2QST5ri29NY/vF/E6rmIoiykUSEQ6VAAAAFQCAYk3QEfDNrcK12XbKQY3Saa4w1wAAAIA6tFh1dEeGmw57AiL0ZBqHSV17sBWuZlrAr1kHCENRqAvnyBLw+9yw01WFLZ0oRfjmmpmaBrK3ZQQT/luR7f4J1m1K0Ox7MFgy7w8j/SqM5QuGXvEslPlrIIg3Zm69wfy+2ofz19eBmQjPRzrwDNjVkWMk9z5N0TSm4j3eYxVFqgAAAIEAslyMZiOwYA3oiFMQTJEphKdgejWsjqQ9LoKppfZ3d4Jj1V3tgI1s/wHfoneUUrUwM+sMHZKXbBDLWWQUOSIxDYcXKDkbZ1FlmhvJR+45D2LyLKjEnjVDlQCwYly4P26zXqciZS7k3H/DjiHtAPUeoHm9IYb1A03K8Bd/xW0guMc= testuser

5
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAqXVKoLNr7/wNluxmGZnZmJCD/5h06ptAICRk+8FIjfoAoGCCqGSM49
AwEHoUQDQgAEoQHTUWwu3nJnCHeSv3YE59UxfuGNjAXLzK0MjDwoXt6/qePjjKAQ
ehHdAIYQHr9zYJu5SA5b86HL5glqjcy+Pg==
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKEB01FsLt5yZwh3kr92BOfVMX7hjYwFy8ytDIw8KF7ev6nj44ygEHoR3QCGEB6/c2CbuUgOW/Ohy+YJao3Mvj4= testuser

8
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass

@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,86940587F5C93441B585F469FF31AC06
LaIyzOCeBPJA6OkFOFnFfVorYO+Rm1g5QpvqEcFZ+FCuEvhMZN00NMZ5hHKvwQLt
XSK5Se8MUD+e6qFH/ZcoYTixUqYjYJlOkxJzKaXg5nM82wQHa1LqQqcL4IDrJmzv
qJbCLtl6XOfkQQUA6gezqhtiNYWLDZIPfZ0dsaIB/fU=
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKEB01FsLt5yZwh3kr92BOfVMX7hjYwFy8ytDIw8KF7ev6nj44ygEHoR3QCGEB6/c2CbuUgOW/Ohy+YJao3Mvj4= testuser

6
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384

@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAgAgPcgkPaitxOrphrrLe+am0eUhYi346UUTnb5WZL3164MEjFByd9
Egv6KwB4hCqgBwYFK4EEACKhZANiAAQhJrJ+vJLbkbd9C1he+4XuxaOyZ1IqYJqz
PZCXcKkIlgy+0I07RAxRUd75GHKc4ViyUnLq5odV25H6FNzHJHO7ifE4H6jrEpA/
UL6LkfZReYZ4sNmeQI7MBXm2IXQsIZ4=
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBCEmsn68ktuRt30LWF77he7Fo7JnUipgmrM9kJdwqQiWDL7QjTtEDFFR3vkYcpzhWLJScurmh1XbkfoU3Mckc7uJ8TgfqOsSkD9QvouR9lF5hniw2Z5AjswFebYhdCwhng== testuser

9
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass

@ -0,0 +1,9 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,80B1C4D6D9B45690A07B9886050C63A7
WxS7EGs77p1aPZuxXW0G/yTFKAh4M30AaeGQBPjDR/HTAmPJe3irDH56fdmGhY4+
zBT+6X1VppB+UqB0nJ/qHq7FeA37eJPXJnuskPh2BzLlBaVhmEnzZylEW33gzAuH
XzC/Z2OjdWRjn+rBXM5fwo9IIC0WzTNpBokdeMo8tpnPzGTlsTFeyVgMZJ3wOlCO
4ItX9ddY5P+MrLzWP672IyZZqAQGfLec4YoJ286wpHY=
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBCEmsn68ktuRt30LWF77he7Fo7JnUipgmrM9kJdwqQiWDL7QjTtEDFFR3vkYcpzhWLJScurmh1XbkfoU3Mckc7uJ8TgfqOsSkD9QvouR9lF5hniw2Z5AjswFebYhdCwhng== testuser

7
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521

@ -0,0 +1,7 @@
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIB4zI/MCFSfJ0wfyLwZPxG1vP2o3fF7fEuOTpK+fxbDHKYz6r4bNv3
HkPQEVTIAqDl7r5Ebcx0BMeYr9oe69tPZIigBwYFK4EEACOhgYkDgYYABAChltEM
zT8dXwIhQD2iuy7QbaBkhWMhpFaxztvzSQqoTZvBgBsOmSr9frFA93lSQoHD1Bge
wuwBkNGm9lRcw0tEgABqifONkj07Qj2847MKS1iiVu1sHh7Ys3YimyfJc+nZRNi+
W03nkcdvWd6PP8y/VENoV7+BtIO9txj8Dt5LYOtFgw==
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAChltEMzT8dXwIhQD2iuy7QbaBkhWMhpFaxztvzSQqoTZvBgBsOmSr9frFA93lSQoHD1BgewuwBkNGm9lRcw0tEgABqifONkj07Qj2847MKS1iiVu1sHh7Ys3YimyfJc+nZRNi+W03nkcdvWd6PP8y/VENoV7+BtIO9txj8Dt5LYOtFgw== testuser

10
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass

@ -0,0 +1,10 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,7070032284B3C310353B8C352AB2D8CE
UBgXTwobcLX1VFtQaLNiwwVzdN1+TlmhSRCnU+kv2EpunXxfvyOVS1mZTam9NyhE
O0Mc7REi5hDHp8UYM7MP+wrwK+QM3D2Vm2/Rh0+acd4Gu2XGACJHWXGIyKwNsU0R
ZddusHIi+979sHw3vSUFCvuDwc9YZBoujpzls7NYEWXiAVv6wd1RCtAynkBk/uvc
1F7iHLuRttejBPvrb/a2AxY0pFpCuCVmGjuiS5bfVWBj7xLEplqdU6/95rd9pRwx
e2uRlU0AFiQGNPStfhjgfCWnmf+aX3vAgVqkLMYKYQE=
-----END EC PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub

@ -0,0 +1 @@
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAChltEMzT8dXwIhQD2iuy7QbaBkhWMhpFaxztvzSQqoTZvBgBsOmSr9frFA93lSQoHD1BgewuwBkNGm9lRcw0tEgABqifONkj07Qj2847MKS1iiVu1sHh7Ys3YimyfJc+nZRNi+W03nkcdvWd6PP8y/VENoV7+BtIO9txj8Dt5LYOtFgw== testuser

7
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519

@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBIJlrW8XB46iAVY0XqbjYKG8wJ95iILxOb5ONQhFBvPQAAAJC8jORLvIzk
SwAAAAtzc2gtZWQyNTUxOQAAACBIJlrW8XB46iAVY0XqbjYKG8wJ95iILxOb5ONQhFBvPQ
AAAECjklggj+glO2K60Ptg+aXYGBdvXtk9TQnKINhrEIxW9UgmWtbxcHjqIBVjRepuNgob
zAn3mIgvE5vk41CEUG89AAAACHRlc3R1c2VyAQIDBAU=
-----END OPENSSH PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgmWtbxcHjqIBVjRepuNgobzAn3mIgvE5vk41CEUG89 testuser

8
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass

@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABA4hLhtuV
MNBBC+j45F4KFcAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIEgmWtbxcHjqIBVj
RepuNgobzAn3mIgvE5vk41CEUG89AAAAkPH343T+NbHb05J/6CHnF9h7C11LJDHe2x9+HC
dNB50fP9M+KJ/cC5cqIeHm8y0fg+wX2WLlJPjNVoSd5MciWCfUWO0k32ciVpoyrGCz5Gh6
axKVVY42QjdgO0S2QxWClnAuMdkVdl2ke/PcGp4yqTTIruAAB0m3d0jZdKNT1Vziww0rQB
+DOo7xQ9Tx99U+rA==
-----END OPENSSH PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgmWtbxcHjqIBVjRepuNgobzAn3mIgvE5vk41CEUG89 testuser

15
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDGfj0Jmqj+CUb+WdFrlkRV49TJtNzvvMb/nX20zqgGm50cOIYr
MzfFpSQN630pXeAidIgiV/PWAsipntQfSWPRG+RpB/wMKHVUNPJCJkjjRFEa56Yx
gAhgNwF511K13x4p2tEN0r6wsfw1nos9VoO8XDBAu3lellAgBdufyCt8vwIDAQAB
AoGBAKU+bNP1BGDQGmEfJv+5DlSuofP19MREVSpx0zfVnv45SFc5G0EVl4Wb0GMi
O4VXmIM2nipxLBZrJOBI0HDnaQcx1zQR6tpvBO7BbAU0sflOvUDldUStTnz3TTQW
2ECm2y8bsArNqkeLndqis3ICmYL1budhDdUYYcqv10IlbjPJAkEA6yE0zduCE2wM
Ob7lcqiQCOiXeZ0KijHTmSZV4Fn4HRbp+XuxUpjSWFaoDTO0bncGNE+JYjywe64V
XvEORb1hTQJBANgcjEoCrUFY7VYWx3f1tpN0Q6jwwcj67Sd+ysaZNgghTPU32GTa
auGQFv+tifUQMyyVrhAfZ6s8myKOH5SWUDsCQGVvqOkaRq58UXXkDfZ+E81UEm0L
u81Mm52ZdTjZd3mNNhlELIaWmUA0+kDfynpRbOLKYVl5FyX0PxH7ao3Zmo0CQFpL
+1YFLk0KkggRdoCp+wI7ZvXUurN2HNcOxD0c0RWujFA9aD4jgNsEcIeeA/GQNkGf
vN3hsVg793oFti5Ia/cCQAubCMvRqFTyXUBervPVC0kibO3OwYt2xN/7lQXAVSfm
nRwV/46trioV3rMF84hpOk/46Qe5hqbWyQnL+dZljpY=
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDGfj0Jmqj+CUb+WdFrlkRV49TJtNzvvMb/nX20zqgGm50cOIYrMzfFpSQN630pXeAidIgiV/PWAsipntQfSWPRG+RpB/wMKHVUNPJCJkjjRFEa56YxgAhgNwF511K13x4p2tEN0r6wsfw1nos9VoO8XDBAu3lellAgBdufyCt8vw== testuser

18
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass

@ -0,0 +1,18 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,4B8025AB7456E0A2B48408407C6E3FF4
B9gztX+5QQPqMR/79eJHxjNdo9baoKjfWY+Ye7t1h7ucOPMCEXRSP8FwPwBfbzQh
6W1AHOfiDCHTzArDRG9SXrFfRlU+8o5ffs/TStTNqde/AXJeNuM3pwbmqKV1m9oY
oWelabmGtNUvGMAHMFm/2uk4BgS9Kjv71KnJg0cQQfIiPKTPBncJe/R5mf6O12rB
ByOrrlDmjtgveZZsgggEZbU9Y9DYiHZp6yT0JepxIWNImQ/A9EeUPTQheVB2ECT6
DLUOwRfyFhdvsfD2eXLK+u7T47keFny3rIfm1e8HC1y3X+T/nFxKGoShecx1NmEL
HMgOKyFSwGSZh5jxE66dSQoc+rRZhCWSyPJEb9cjwp8JLON8oH3Yg+PIXYJhMFK+
nghAIVXp3/H+cYXMN27j21cRGC7ePuF3YX242Gr+LSj42Wf4qCMTyvWur8WrSe6U
iyrWJ8+w2J7O7rRHGM8v+GYGaiX1qIXFheM/774vsDmjuueOhkjiqs254gaap8xk
LcJUuqJU2AL21+eW+R+EG3Rl/AbMIaQ4GFDpHfgEmmvVVoOvJunNQkDIP9JzKczO
g7cN/EYLUC2TcdmNaiunB8RhXMiaTqw4kYJEzy4lsxk/xjubC7vlQKTvtnWCpob+
WpHX/2FBdPPULt38AIk4HQq7vKvKw9TmvGeOvQmCUun7eCFFhxKrwNKO5YCXAHvs
fv7JNGfrST4jwbqCvamuk+XTf0GkgJN83G7DT04EIzee6wwai/NRDybgYptJsj9G
6wBpKH15BtkktuUzM1MCt5+T6Ccsg+d6xE6eStimwDxkXCjvgz/KlS+sPKe7uS4h
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDGfj0Jmqj+CUb+WdFrlkRV49TJtNzvvMb/nX20zqgGm50cOIYrMzfFpSQN630pXeAidIgiV/PWAsipntQfSWPRG+RpB/wMKHVUNPJCJkjjRFEa56YxgAhgNwF511K13x4p2tEN0r6wsfw1nos9VoO8XDBAu3lellAgBdufyCt8vw== testuser

27
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1sFEWiIp8SVO8/sDhKJ67O7tQdtDwsqWi9Fm238tAuy26OH+
ylireX/qVcndU8Yr0qYShcwloEUaeNe77VgffZa2ZIUee75u8u+WGCYjea4RQ1bZ
tDcioWkxl+xYfVuuKaA8CQn47XUdyoA/5P3DpDhaJl8KevaYupJNHOo9Lt2E5dVT
93OksZBOQ6E3nNlsefP/hnFByiczlde2GIXP2sWLoxsiVsbI+CLeGtxQxPubX9yu
vWrl/nv/yERR5ZBOEVY5N2+1BdT7DvOIMg2q60FpJv6zZpQi7Ov1iONMVafytIRW
Ma2rPkpS83Ebxh5c92T3rgLUf5DcZjKvBgxtpwIDAQABAoIBAHeDZv6iNKU3FhFB
iFuv8Kka7n7P/43QIKf/CTbuN6aBBenkm18QqZ0cStUjWkDc8FZyhaxgSDBBRNIr
fTJA8IV78lVOoABNooEgRG98ChIVhRXsp4tbg7JAUJEzvqtE8k/IFKETI61CmCmx
5d0SPGaP1du02KhFxAlQkgmdch85st+tRFv5GZXqiKbR6QlNaJgIXIoOlykVvnz6
rnl6Q1SDutBOKGC8xFrDzFI8KxLFe3RFQxtHtsLRPcrrpukNSHICTMO4jtGXSZ12
9Zh29ZtkouCDk+b176dGrJKfIBbxXtBGVXtkuo7rj8EWVWrJiiYbL2hcWD+Pw1VL
0GWkaEECgYEA+RrE4nVkfdJ0Zgx+sACQqs4uKi/JuFHU69JnO7RB2lDwzQbIPKl7
nn0ExJ4V9m035/3mqKReBIyMIjIhwXgLFiakNO/+GAWa4ycRMB3pV8WaVFCnWZEF
oLRg1ukoLs01TfOszcux831n8zmPlz/NLTTkC26O3WXsVmnCSlPXd1MCgYEA3LMW
B8ONEDFYACB8xKA5zn3jrKq/yVFfiQzEO87zSkgG1mQbsb5T8jggWiIHVyZKQUSk
8ZkrwBKW+LwyRik1lVwawALmcvvN3VyCW5BukniErAUu8jb3+R2aFdrjzpiNqzMF
M18BPDElirTXMjJusC7z/0I7+gyAu9ttYJY1id0CgYBqjIiqVIwnRV2ESNPndFZs
uMQGR2qA7H+mXtjJMND6EKTvDXeYeuXlZJQlhXjfbtf64x9GAwgz6eoGtmq51h7n
2p9iBUUqATu+7Xbsnd6xLFRWvCjYpq9BjeXeBtypKB0kupWvcPEstPdBkd1ZVHDu
ZTElsqRpDq+IRrRUFoiTAQKBgQCxTGmRWSa08H8asv6o03M9EONbrlyedXHDXu8y
gQHwFcbwasHY2+cCetZ6skWlXIxgvK2prXx5NDX2ovHcbXSvhauzv2C01NdAUvYi
avh5ULp8mzlouoIhrgdAMXW7XdDJzRYLe/I5Ed5v/PG4UM2dWksIMISQT4UH5bKL
2oAuPQKBgCQaJ2oc5qE/f6MiL0XfGSdY26gOZcVrm9L1XKXtyHkfj4xWYQ58DSYa
vNZH3fGyfR+q7g1WgUmLib5etOjUjbVYRjIEov8xLA41UZZLNGRLc4VzgeCT73CW
YvbxeN93fL0tgvKeyNVzIsWRazHMo+aQodlXvpPckHXYxYHS93W+
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWwURaIinxJU7z+wOEonrs7u1B20PCypaL0Wbbfy0C7Lbo4f7KWKt5f+pVyd1TxivSphKFzCWgRRp417vtWB99lrZkhR57vm7y75YYJiN5rhFDVtm0NyKhaTGX7Fh9W64poDwJCfjtdR3KgD/k/cOkOFomXwp69pi6kk0c6j0u3YTl1VP3c6SxkE5DoTec2Wx58/+GcUHKJzOV17YYhc/axYujGyJWxsj4It4a3FDE+5tf3K69auX+e//IRFHlkE4RVjk3b7UF1PsO84gyDarrQWkm/rNmlCLs6/WI40xVp/K0hFYxras+SlLzcRvGHlz3ZPeuAtR/kNxmMq8GDG2n testuser

30
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,DED10D02EF74A02F24F46AB44A84F4B3
DL0M2dNu7cXNLE6KGPqEt3pSKiQw6ajlxYaaXyyAwvpZB0Pv44HUjXfhMONs5FH5
rDjz1RSYDRdMF/h6FtltdEEareXwMtRTvP2wb0gsQKiYS5M9WeebM3TY55JmwS1U
hhrPrEaP6hs6WEy9xp9DVxJN2y1MA5iss7M+fQ4/C6QeSp9On6bgCEvNPwdMTS4A
3sLp+yzRvrefQmSi2SWbJoYlChitOMdc84iDJXDo951QQLX75GqMm41fFLHHrcTO
7v/k/D7p/KLlNf43Ru+2yPNE7qyEK0pDSjvPnjPykIa6SWq3Qx2DnVdtZ7bWF8LA
B349QmuE1r/YYHNvWnp0/5SztivJk3NMeTT29PIiZoHioo53Vtru6RcXYMOvHbh1
maioVkgRl5gkhLC86o4V+3hiJQNrVCWMuT+lxLY2Tt6bFXulbf3WH69AEAFW4S4a
e7zH4fwvkSwz+bFxg9B+Yynv42ke1a+tvDI+aDvsMmv9JUCy6G4Te+isXYxLdtT0
nyqJ+wwP53AWS8gOvoUXzxxsEchTDtQnBQMWuSHEdFrk3OLGykNN6vZaxUROxpJf
vcPl7JniWGhzDzUdHh0AQbLxXoZlv4YU1uO/+1OnrvIkuO5DCDg8v2sTFRW6sgiU
JXm3QPJiU/bu3/FJ4XCU75cTcunZMXsL7TY9mURq7Y5FxcByuvSL2nlA7KfROTVq
I6w+Ej+r99C1u0G63sk5b99Pm4cb2+V/sr7pslqlU9Yw1Z5hw55ibih04CiWZAhJ
Az7s8ho4dY9E1n/XJSe26p14RPYU+w7WZuN6Xb04t3+BhF4Ubbsdn6F3lAVOrrWH
6xNoncmIEYdfdcI089UPpV4/bIpdakXRIbaLmpshyU6aIRUXqYkzwduXcHUrxgq3
1QCZHNvq1+9i5Wqj8JP8cZrq9YVldOeXdIIsm1SSepbDQ7820d5T4Dk6cj85BXYC
6t12UNZ5mhzTvIAqbR3Who53jQ8cY0MSVXR6Jd6vPih2OhAnccnuJmRCNNJkL4mg
pVcsSgYjoUx+w6Ou1muCIkkGpdEhLLwEnKFc0HUmPBToRqgiB1Aec+7oMv62XhXe
yA26/dpT6N6SWYKN7MyDWUe2ilkmjXI+JrPCH+/w4FXh+GKafOn8XlcBnRWHVBEX
ZQfYLckd1j9B6p7By7ed2H+8FxZLz3gthcSxRG89IP/EQImY/e9A3aoLrFX6C/W0
Gd6JrIvzC2bZCvrq+VTYs3101j1xe6ZDJnq68HokjpG8P9DlFYDOpRetCjR7TuqN
I5s606KAsGkt/jfbSNUMIEtuM0AC75m3TTJeWdfYh/PVYevUC+pUoreJ0ZsttQ2i
D550sAAzU7PCzZQsDF1i2jv/YZ0wXz7+C7YFiGNmb3HmXH0Lb2HISJR5UL+x+hHY
RArXtVubqjFz179pawzI0n03Z1OXiHolwer7C+Twmarv7SPe8rMU3HcHP25JeTAW
mo0PxNGG3yQPlRZWpPz8LEWGo+fDqfA4kbqy4+Pvo7B8YFIQyE9QG+oBv+/7uqMU
UOs1ZqsmvEUmvWMeQnWsjETmHKucbmTBm8ktsesb3sCKfY/pf8hAHbO6+9J3ebYf
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWwURaIinxJU7z+wOEonrs7u1B20PCypaL0Wbbfy0C7Lbo4f7KWKt5f+pVyd1TxivSphKFzCWgRRp417vtWB99lrZkhR57vm7y75YYJiN5rhFDVtm0NyKhaTGX7Fh9W64poDwJCfjtdR3KgD/k/cOkOFomXwp69pi6kk0c6j0u3YTl1VP3c6SxkE5DoTec2Wx58/+GcUHKJzOV17YYhc/axYujGyJWxsj4It4a3FDE+5tf3K69auX+e//IRFHlkE4RVjk3b7UF1PsO84gyDarrQWkm/rNmlCLs6/WI40xVp/K0hFYxras+SlLzcRvGHlz3ZPeuAtR/kNxmMq8GDG2n testuser

39
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072

@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDUzzht4+crpxH0SL8fRLfpCF19SXSpQhlesc29L2L+elNl03WYLNbF40ebRglBamf0Co9kYb908a3cJAQvnZMpdrBj/SSz7inQkn3brSipUEUmtcTmVq1VAJ0hnUZHaIkveRktcddKRRHKAQv1oF84RRKYLhKQ1jQs4a7AxnZPJeIVYctj2V7UNTZQxt+Trn7ouDNT4UrM7iyD/NkPegH0D6f6jNJm/9gQy4+9QBugxQmu7+5zoPlTGHAnoZIo2RK3fElQqeyiGQJtECr9qey9UmoSyBlz6gpUWJ0s8/P2suOgSXfD5xSUzRNttdqq0VcKgTxLoIAkb8blGR+vDttRSSMZtitWqNHVbfZ2De3HNkxWiMjOiUHkta2xtljrbRv6EeTtWH4XdXDbKKcY2s8NWdUzAH6lEKw+RZK+Uu+lHgLvGqqIS5wHV4WrBZJWF8ODOS+1OJownszti6cnmkVaM13TItk2AhrlIRLOufnrjDCNzAFsxWJ+KYynem8UFus= testuser

42
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass

@ -0,0 +1,42 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,040847DD0487D72145EB88CB09486EB0
2vC15lwRqJvaSU+yYCmqerJft8dqlrx9EK3gW4WtMW6C4ebqlj5DkIthSvJLgF6O
wufFV0hgmEeOhLEIrdJc/FTeD6VsSBYHTttoMeQ0Yb0eETnLhSbFO+9NRvPBpT4/
EsBozu1m/fnv14qbXtgiX9d3zRR5Il9Q/TP9/MO25QO0/7SLHn8ar255piZobBQ4
xqW26UywI9pUMjcfgroE4PYZTqTPY8xGFBeOIXBGuw3m4geKcOMbiPehB2o7gZDJ
iC2conFycbi0xUBYytnRO4BboB1PhFnh4CXFqAkJycWj20Q2iFVliEXEey+Qyd4m
vu9Hr1sp+35kByS5uQ7UfDgBcoo25JKz3HIcqFrSzJ3cwRuRrj27eydojR12o4FI
Cd06GTMq6khN3lovVUaQWlE1MLUpT9zT0rLzJylZ7fgHi3cTZ9n5Nr70vX8+pvFA
mzQ/53nvXQkiKfyUWV1aVypNsl0kYEM9+6uLyknyUPmLDOGxwAz5bS2xp6J7BKku
PojN6NHChyqndHArpR6EUx8RYCQV7PL0EPCSVlyiscetNBfTe9+BzCbPisorukQT
EweviRMUmW/pdr4zPuMwfZQSzRGYZ+19sIfV/VsRvgYvTUqUZ4mvWQbyiGpeLoM9
W/bAJrqJBgfMISw4n+j3oVd0HJULWxktZGD8grLsmeh3Yjk5TCXcv6dH5OGx66nR
ATMjEinVcwop+z5RdlaP48Lw7/FfaWTiOln9O9DMT1pjbyO01qXHCKvo+TnSYryK
SqqaomMm7vMQMytxPPZGuiSCKpaIWwfMLIzreFw2LdvzGEF3wX/SBW+8g30hwyfq
YKrP3ZXe1g56oRqU8S2dB69rkap4nljj4HSXvIr/7XNQpkKlJX8yOAncGUcXfBaB
kIytyAfX7Xfibk8uPnDFxL7JEmCMR78LP3jYLX1Icl7lLdbUFUfxb2WM6Fng5qyX
Ffggcd7gucydjFNKR/KYlJVCIfxJTt9D1tGz9MT0sk7hSEIlIPieG2VkKEYKHbUj
UHEwbPbeFxm9INyccBAdnCvqfJ5ppQKB9TrZliPeLclx52NlX+3gtBErneycyzOk
oQmFtV+Bqg2hgH8TDLenGmG2xJsviuNTXeAjyZFLXkE1kFAPEKmz3Bys/tSJ+NTw
mAQxRnZ14BmO11o+/3xrrA3FkxiZq6hVUOyUZ/rejkbMTXUb81kyJe5o0kgLnQ8p
EJGi6tQl2z9YPQC9wWXO5ssu+Q+5MJ+H8YlvV6oc0nXUcLq9mgxPDPRBu33n79zq
mKymh4jO5qTExqnC6lLOsw7YVsss91opBLPGO8nXtcRvtqiRGwI+2D9kUVHH4J9R
dHXQaVXgUGxmhJFUxHEEckrT6NN923uY13R9Uw5Ifmh3XHob2hFQlbBP3GeiwfTI
DlNxIEguXxuZddJD2Fg/vLn5KNzkCOlYcrvoa+eH2jzcLN94tLNjliOgX69eERdt
qjz3x8Xoyh/bWcrdw7LZC7PtjwfLlkoubUVtOv++ZN4iR1XEjmEuyzibOUTQ8Ydz
ZwUXchQKupTxEGgIJ6tl7NGXSjA/TT1KYQUgVil9Uv5zZbOZecFClFF+1Vcmuzgd
hLzWG1DhZzvEAI3whQafUZf2BuyfYdnS2aKjVYR+k9dCTKAIz0MWOl29BC7/v1L8
d7uqonqiVhwfHOjnUH0cD+QRM1i63+Luyo4c2WyCnQ7DFOfs5l+SwnQL1Lxu67F9
7lGr2g0l721hBTaUKMETrTjNSz/OBURebumgMtr+45K5JCj8hJ2NFQUbmqkqhyf8
f3niFJymhtywyUPafsodRbQhKMVg4TYVzQsRnpdsQ1IOFt3vcZnRNVuv0Y4bTXH0
TjdwxAxtxtulvE6K7esXTQdElW+yH2Fkq2edHsxquf7PoMhBLV/myMPq+4inrLU0
rr+Er/yYLZLdolld849WTtYdDB1GwcPQ6PmuBTpt5ccoFQDvK20U4uG2EswpVkoY
YCWf9sUnGwZh9YE0h6Ag0IY13CeQL3dsiua0+xsVEOiAZ3Y6Mawb7W0VZPHo35Kh
ettpfjDQUF3FA/J7hW0qa4soapbymbtlkOjdQMe3tOV28ElWe2ve/TmDvUtVVB8j
y0vjRJtwkcONM3CUuOiJPHKFvKwUBAC+7VyvRy2lRPKYVZibIr98fyd6BXsP4tD1
R9e+Me6Cq2UsC7ywii9DmkBqpSP8XBOMNdBzbDN9gPnQzGx8oXo2w3mZZlfJe9uK
v09UMglCxrYBDw30MEfoF913crEofxrHRSzp17tFEB74M/r7OmeegSCD8Ud7twH1
mpnZRlGanu2DQrEmhVpfJxjn7pHPmolJsQirFfVY6wCz5UQ7iXRV3LILnruVjpIZ
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDUzzht4+crpxH0SL8fRLfpCF19SXSpQhlesc29L2L+elNl03WYLNbF40ebRglBamf0Co9kYb908a3cJAQvnZMpdrBj/SSz7inQkn3brSipUEUmtcTmVq1VAJ0hnUZHaIkveRktcddKRRHKAQv1oF84RRKYLhKQ1jQs4a7AxnZPJeIVYctj2V7UNTZQxt+Trn7ouDNT4UrM7iyD/NkPegH0D6f6jNJm/9gQy4+9QBugxQmu7+5zoPlTGHAnoZIo2RK3fElQqeyiGQJtECr9qey9UmoSyBlz6gpUWJ0s8/P2suOgSXfD5xSUzRNttdqq0VcKgTxLoIAkb8blGR+vDttRSSMZtitWqNHVbfZ2De3HNkxWiMjOiUHkta2xtljrbRv6EeTtWH4XdXDbKKcY2s8NWdUzAH6lEKw+RZK+Uu+lHgLvGqqIS5wHV4WrBZJWF8ODOS+1OJownszti6cnmkVaM13TItk2AhrlIRLOufnrjDCNzAFsxWJ+KYynem8UFus= testuser

51
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAwzbSXgR8dM/EU36T2lAKUoRlojKspPhKVfDt7N3prGAc2L6A
P0y3G1HLLgKPK29S0Cydcqyl694ST+uu9qYzDLQlFQHbxIG76POmHXj92bF47lJU
RNxi78hoEDnZWtDG0rsUCBD1I4z+tXjWV81pv3BqVg5ilR6uqNgv3RzXj2jL6Q+3
zwXxeMw7jJ3Tuukhf50hlxblH4bBIOLuZyb4t8R4EyXmrAPupHaUZSiwbxaDrV+s
gdu/7G8dnyB0dVL3AUNUEp7Wrh2PewnjgUcNQQmyJuB98wEP3+GrTsktixjIEmCd
e/gfDsl5JxBzzbUFtlQ8JVOnn9JCQ2U37cRggsW3yojFxGCU+bJaXz0zSgPmfR/r
T7oXgDKR76JZ2VSTGuAFrPcdRyErPg4PC6FtW0mNxn2S6RK28s6xpTDywEDu8ETh
lKIXGnN9XDX26gYw56ZlmAaJQ6KQP/F0Akf8nRARzkPJtIa21iBrUHRXLF7YKnBw
LyCUgTA3WSDgNdP9Ga7+6JC5gGPW5KGIKoK7SZY9LxNoV66iglp0nGEM27ZU1raw
llwcJAzkbSaViD/vvrIiuz04s4+5K+rAhe8CU4UTBWUJgUvtTSV7d/SBfFLsQJI/
W11n9+SCIbBCx9nON+xkMkMQVyrMPWoD+oYRx/wXGIO2qkkPeegGyb8oKYsCAwEA
AQKCAgA7qPx/yUUz+e9ZSRzsonuVHmtlN7F1tYAaZciBFIz+pl0KjKXrMonfao76
38NbleksQAZabpNC05qrHC9bqA1/+2o90lSU6MVB+3ywEzMZndiElVq1tNjzyT6s
ftGDpLyu2IfVs0EH/WY2ldiD+v4viK6m4DyWsErWxUNTgyYJ6RAwiSI2ve0/asNk
RTPZMriPJLmIUHHzwZ4ya8hKdCmdGAlOaM3nkkgTsT3G8LmDKdFSYiP5h+xO2OKn
qCaPWKyukSIXkr2vds9L3gjOkKVnVAxDP2aepptwY6qUKH2nvgofO7HFml37ie1h
1/BcVM+LGpFLIxbejEa+DCgcnWCU7VbWRSvU3TeV0uTdrGBhKSHLBMigyqtt4OTw
QcWLd9zygDO02Jm9vlMO2D6WmI0medbgXPT+vwFBXvt6/Z2sNf2zW55qXn7yeFlu
7/GiZFIlpH4jOw6U8uG6YV7YueXSaKmbeI9hSB4d8hrRqud0Ny7fu6m5+/GB8Q6q
2cZ7mETvrNmISe4waD9xk4CP7NchM0LSU2RWP5VtZAHEM2iIYin27aI0GjdhEm8Q
oc5fU+kGJdLiMZ7IaCp2tZZ16PLjtWXqdbCgqjmdp8jwtwLuMil9XAFHm22jbrnP
/bFCnlNLcknH/csS0jVxZI+nunS9UgMZVCudvJ8lzY9LDlFUcQKCAQEA+b5tSOfC
EVdVY5+9zvx2glvQRxqN/5fonMTZXK1qqVNcbxb5tQ9I5uBQCykg7HJ30ukgK00+
qbGCc64l1XNu2dFFXKJbSOV/8Ts5vzfmgdwZoC+W4IwojRQmfyKCwfIsP8IwrBSp
IlcO7LMkHCnlmRPPMSPeQ1NB/N3mnilz0I5KfihahziKccCTGBvpESD945qWqCrL
ynHmuEyb1zvwU8Z4psrfiP/RosFjItVJpsQzeVS3CGrTFe0b4PzrIQo12wPXhUX+
um2WMQYoBVZzcrRSIH31RY9PJ3avbPJC8RqGBAZov0Zv5KvpZcL1EeDfBn8leld/
eCpqIheDiOdewwKCAQEAyBq0DF6Qhz5Rl7CJ7BxmaN/CbW4aHw9m9dfpNVqqi36Z
ODfpb0sl40QnRLeWByfDj6BdhTBc3XXcIDVBjsstnnX1IAc3PZgzaONrmDaoIUfi
GIROql5l86tMSjuW53eGze713z86GhvUv19r748asaKTepXgssaY7ppXCZ42dKt7
0euXYyJSirMmO+A98wOtqamKf0X2FK/ZB7CyfhLFskHEVO2noojvZiJwAyz8zvm/
GpOArbRTjEfg2Sqxk27CATVIVjVc4LBzsZc9mzLKVb+Cs/sZa72gy+gLmIM4ItID
+FPW8NbeZmVngiARJcIL4alxXXy+p/uXBILxhuLtmQKCAQEAzzlF3seGzPLFRGuo
iBYNk27xa/5JsrnuZh4kKXUvWp5zxS2wNp8fI4sef5Q54Fe+uv97FNL8WruSfcAT
XoBwi0XMoueIjPz440X8TYDpv/jMPpEeROWnRCBjLPyKuLjkJGdSEYb3LCpGlPqz
zLaq7xBzy9dyNjTgPRw2nifRFEzs3K9JJogwv+BFbSzDf9X7NJ7xwUn5XNqT0Xqn
mLkAWdMGC4esYTW7UavbQWzutvR3rYYwdUiGK9xZVJ8nznt1YmxWqRwCF9iUVctA
6+Tm2FdtCc7Z9ETMLfeZ6fE+wGX8q1xSD9w3PeuzNx/ET3hiNjbL9y6g8ylmdTFD
kBZDFwKCAQA2by0zgDYI1GcVwKyEUmV5egVGB4GLmYEEt6t1HCjwsYu0w2D5KZQw
8sVL6DUj1SlZ1OIb7UAV7o3nJRWkZpkOVkBMaioY02KI0fTe/19VTlyvFq7fobZS
RvMF7pfqd5VwR+USyfxgRdnmBWszS9aTJArCeisZ9vR7U/kBYMyniE6ymEgia5/Q
o1NvTl0L0qBXWwuV+84pany7ntGvgiPNjh5+i/fiOyYEvrGB66cKFt5puF504m0n
6BW+feK4nJSiB4CaEwIlDVsroFzd7z8jfGlt1IzhxkALuCAPaQLIViFGWGhMM+dk
K4mw2FBR2SuqQ5HXQKwMvmAilgxmCS1hAoIBAQCykRU4k5qTxoNWfkYz9oYxsLUt
FnyBoLxAzGrzM7F3fImVjetXoCow2xRxHnsD4dns7OdE3VbuJrbUDFdvzkEHBT/i
MFJpaF/zrdnKA4hlQ3omccq+y0n1wLcG5LoHMoKoQQNHPO6G+Wf4uA4M9+p0ImH7
ajEf/Rs+PC3cqKuvJdoFpSOseFNwAo5Vbc6N9nVgFfuaZ95puKgq9BzdCJnpK0Ss
J1K4VmpE98jBMYiEAAVPBdLA01nBiAY+Nwdkh4VjAJ46E++5pofTm4xvYljxIoMl
v7FbW0X6S4azOtIrGJ6EC2mziz07PA2Ad1zf7yPWilMfxC8mNIbS1pAmcVoy
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDNtJeBHx0z8RTfpPaUApShGWiMqyk+EpV8O3s3emsYBzYvoA/TLcbUcsuAo8rb1LQLJ1yrKXr3hJP6672pjMMtCUVAdvEgbvo86YdeP3ZsXjuUlRE3GLvyGgQOdla0MbSuxQIEPUjjP61eNZXzWm/cGpWDmKVHq6o2C/dHNePaMvpD7fPBfF4zDuMndO66SF/nSGXFuUfhsEg4u5nJvi3xHgTJeasA+6kdpRlKLBvFoOtX6yB27/sbx2fIHR1UvcBQ1QSntauHY97CeOBRw1BCbIm4H3zAQ/f4atOyS2LGMgSYJ17+B8OyXknEHPNtQW2VDwlU6ef0kJDZTftxGCCxbfKiMXEYJT5slpfPTNKA+Z9H+tPuheAMpHvolnZVJMa4AWs9x1HISs+Dg8LoW1bSY3GfZLpErbyzrGlMPLAQO7wROGUohcac31cNfbqBjDnpmWYBolDopA/8XQCR/ydEBHOQ8m0hrbWIGtQdFcsXtgqcHAvIJSBMDdZIOA10/0Zrv7okLmAY9bkoYgqgrtJlj0vE2hXrqKCWnScYQzbtlTWtrCWXBwkDORtJpWIP+++siK7PTizj7kr6sCF7wJThRMFZQmBS+1NJXt39IF8UuxAkj9bXWf35IIhsELH2c437GQyQxBXKsw9agP6hhHH/BcYg7aqSQ956AbJvygpiw== testuser

54
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,1EFAFB79DD5E78C98C5A2204D6747AF8
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
-----END RSA PRIVATE KEY-----

1
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDNtJeBHx0z8RTfpPaUApShGWiMqyk+EpV8O3s3emsYBzYvoA/TLcbUcsuAo8rb1LQLJ1yrKXr3hJP6672pjMMtCUVAdvEgbvo86YdeP3ZsXjuUlRE3GLvyGgQOdla0MbSuxQIEPUjjP61eNZXzWm/cGpWDmKVHq6o2C/dHNePaMvpD7fPBfF4zDuMndO66SF/nSGXFuUfhsEg4u5nJvi3xHgTJeasA+6kdpRlKLBvFoOtX6yB27/sbx2fIHR1UvcBQ1QSntauHY97CeOBRw1BCbIm4H3zAQ/f4atOyS2LGMgSYJ17+B8OyXknEHPNtQW2VDwlU6ef0kJDZTftxGCCxbfKiMXEYJT5slpfPTNKA+Z9H+tPuheAMpHvolnZVJMa4AWs9x1HISs+Dg8LoW1bSY3GfZLpErbyzrGlMPLAQO7wROGUohcac31cNfbqBjDnpmWYBolDopA/8XQCR/ydEBHOQ8m0hrbWIGtQdFcsXtgqcHAvIJSBMDdZIOA10/0Zrv7okLmAY9bkoYgqgrtJlj0vE2hXrqKCWnScYQzbtlTWtrCWXBwkDORtJpWIP+++siK7PTizj7kr6sCF7wJThRMFZQmBS+1NJXt39IF8UuxAkj9bXWf35IIhsELH2c437GQyQxBXKsw9agP6hhHH/BcYg7aqSQ956AbJvygpiw== testuser

4
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JSchSshTest.java

@ -53,12 +53,16 @@ import java.util.Arrays;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.transport.ssh.SshTestBase;
import org.eclipse.jgit.util.FS;
import org.junit.experimental.theories.Theories;
import org.junit.runner.RunWith;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
@RunWith(Theories.class)
public class JSchSshTest extends SshTestBase {
private class TestSshSessionFactory extends JschConfigSessionFactory {

608
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java

@ -0,0 +1,608 @@
/*
* Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.transport.ssh;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.URIish;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theory;
/**
* The ssh tests. Concrete subclasses can re-use these tests by implementing the
* abstract operations from {@link SshTestHarness}. This gives a way to test
* different ssh clients against a unified test suite.
*/
public abstract class SshTestBase extends SshTestHarness {
@DataPoints
public static String[] KEY_RESOURCES = { //
"id_dsa", //
"id_rsa_1024", //
"id_rsa_2048", //
"id_rsa_3072", //
"id_rsa_4096", //
"id_ecdsa_256", //
"id_ecdsa_384", //
"id_ecdsa_521", //
// And now encrypted. Passphrase is "testpass".
"id_dsa_testpass", //
"id_rsa_1024_testpass", //
"id_rsa_2048_testpass", //
"id_rsa_3072_testpass", //
"id_rsa_4096_testpass", //
"id_ecdsa_256_testpass", //
"id_ecdsa_384_testpass", //
"id_ecdsa_521_testpass" };
protected File defaultCloneDir;
@Override
public void setUp() throws Exception {
super.setUp();
defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
}
@Test(expected = TransportException.class)
public void testSshWithoutConfig() throws Exception {
cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter", defaultCloneDir, null);
}
@Test
public void testSshWithGlobalIdentity() throws Exception {
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
defaultCloneDir, null,
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithDefaultIdentity() throws Exception {
File idRsa = new File(privateKey1.getParentFile(), "id_rsa");
Files.copy(privateKey1.toPath(), idRsa.toPath());
// We expect the session factory to pick up these keys...
cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter", defaultCloneDir, null);
}
@Test
public void testSshWithConfig() throws Exception {
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithConfigEncryptedUnusedKey() throws Exception {
// Copy the encrypted test key from the bundle.
File encryptedKey = new File(sshDir, "id_dsa");
copyTestResource("id_dsa_testpass", encryptedKey);
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
assertEquals("CredentialsProvider should not have been called", 0,
provider.getLog().size());
}
@Test
public void testSshWithConfigEncryptedUnusedKeyInConfigLast()
throws Exception {
// Copy the encrypted test key from the bundle.
File encryptedKey = new File(sshDir, "id_dsa_test_key");
copyTestResource("id_dsa_testpass", encryptedKey);
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(),
"IdentityFile " + encryptedKey.getAbsolutePath());
// This test passes with JSch per chance because JSch completely ignores
// the second IdentityFile
assertEquals("CredentialsProvider should not have been called", 0,
provider.getLog().size());
}
@Test
public void testSshWithConfigEncryptedUnusedKeyInConfigFirst()
throws Exception {
// Test cannot pass with JSch; it handles only one IdentityFile
assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory));
// Copy the encrypted test key from the bundle.
File encryptedKey = new File(sshDir, "id_dsa_test_key");
copyTestResource("id_dsa_testpass", encryptedKey);
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + encryptedKey.getAbsolutePath(),
"IdentityFile " + privateKey1.getAbsolutePath());
assertEquals("CredentialsProvider should have been called once", 1,
provider.getLog().size());
}
@Test
public void testSshEncryptedUsedKeyCached() throws Exception {
// Make sure we are asked for the password only once if we do several
// operations with an encrypted key.
File encryptedKey = new File(sshDir, "id_dsa_test_key");
copyTestResource("id_dsa_testpass", encryptedKey);
File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
server.setTestUserPublicKey(encryptedPublicKey.toPath());
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
pushTo(provider,
cloneWith("ssh://localhost/doesntmatter", //
defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + encryptedKey.getAbsolutePath()));
assertEquals("CredentialsProvider should have been called once", 1,
provider.getLog().size());
}
@Test(expected = TransportException.class)
public void testSshWithoutKnownHosts() throws Exception {
assertTrue("Could not delete known_hosts", knownHosts.delete());
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithoutKnownHostsWithProviderAsk()
throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
// The provider will answer "yes" to all questions, so we should be able
// to connect and end up with a new known_hosts file with the host key.
TestCredentialsProvider provider = new TestCredentialsProvider();
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
Map<URIish, List<CredentialItem>> messages = provider.getLog();
assertFalse("Expected user interaction", messages.isEmpty());
if (getSessionFactory() instanceof JschConfigSessionFactory) {
// JSch doesn't create a non-existing file.
assertEquals("Expected to be asked about the key", 1,
messages.size());
return;
}
assertEquals(
"Expected to be asked about the key, and the file creation",
2, messages.size());
assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
// Instead of checking the file contents, let's just clone again
// without provider. If it works, the server host key was written
// correctly.
File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
cloneWith("ssh://localhost/doesntmatter", clonedAgain, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithoutKnownHostsWithProviderAcceptNew()
throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
TestCredentialsProvider provider = new TestCredentialsProvider();
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"StrictHostKeyChecking accept-new", //
"IdentityFile " + privateKey1.getAbsolutePath());
if (getSessionFactory() instanceof JschConfigSessionFactory) {
// JSch doesn't create new files.
assertTrue("CredentialsProvider not called",
provider.getLog().isEmpty());
return;
}
assertEquals("Expected to be asked about the file creation", 1,
provider.getLog().size());
assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
// Instead of checking the file contents, let's just clone again
// without provider. If it works, the server host key was written
// correctly.
File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test(expected = TransportException.class)
public void testSshWithoutKnownHostsDeny() throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"StrictHostKeyChecking yes", //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test(expected = TransportException.class)
public void testSshModifiedHostKeyDeny()
throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
// Now produce a new known_hosts file containing some other key.
createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"StrictHostKeyChecking yes", //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test(expected = TransportException.class)
public void testSshModifiedHostKeyWithProviderDeny() throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
// Now produce a new known_hosts file containing some other key.
createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
TestCredentialsProvider provider = new TestCredentialsProvider();
try {
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"StrictHostKeyChecking yes", //
"IdentityFile " + privateKey1.getAbsolutePath());
} catch (Exception e) {
assertEquals("Expected to be told about the modified key", 1,
provider.getLog().size());
assertTrue("Only messages expected", provider.getLog().values()
.stream().flatMap(List::stream).allMatch(
c -> c instanceof CredentialItem.InformationalMessage));
throw e;
}
}
private void checkKnownHostsModifiedHostKey(File backup, File newFile,
String wrongKey) throws IOException {
List<String> oldLines = Files.readAllLines(backup.toPath(),
StandardCharsets.UTF_8);
// Find the original entry. We should have that again in known_hosts.
String oldKeyPart = null;
for (String oldLine : oldLines) {
if (oldLine.contains("[localhost]:")) {
String[] parts = oldLine.split("\\s+");
if (parts.length > 2) {
oldKeyPart = parts[parts.length - 2] + ' '
+ parts[parts.length - 1];
break;
}
}
}
assertNotNull("Old key not found", oldKeyPart);
List<String> newLines = Files.readAllLines(newFile.toPath(),
StandardCharsets.UTF_8);
assertFalse("Old host key still found in known_hosts file" + newFile,
hasHostKey("localhost", testPort, wrongKey, newLines));
assertTrue("New host key not found in known_hosts file" + newFile,
hasHostKey("localhost", testPort, oldKeyPart, newLines));
}
@Test
public void testSshModifiedHostKeyAllow() throws Exception {
assertTrue("Failed to delete known_hosts", knownHosts.delete());
createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
File backup = new File(getTemporaryDirectory(), "backupKnownHosts");
Files.copy(knownHosts.toPath(), backup.toPath());
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"StrictHostKeyChecking no", //
"IdentityFile " + privateKey1.getAbsolutePath());
// File should not have been updated!
String[] oldLines = Files
.readAllLines(backup.toPath(), StandardCharsets.UTF_8)
.toArray(new String[0]);
String[] newLines = Files
.readAllLines(knownHosts.toPath(), StandardCharsets.UTF_8)
.toArray(new String[0]);
assertArrayEquals("Known hosts file should not be modified", oldLines,
newLines);
}
@Test
public void testSshModifiedHostKeyAsk() throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
String wrongKeyPart = createKnownHostsFile(knownHosts, "localhost",
testPort, publicKey1);
TestCredentialsProvider provider = new TestCredentialsProvider();
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
checkKnownHostsModifiedHostKey(copiedHosts, knownHosts, wrongKeyPart);
assertEquals("Expected to be asked about the modified key", 1,
provider.getLog().size());
}
@Test
public void testSshCloneWithConfigAndPush() throws Exception {
pushTo(cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath()));
}
@Test
public void testSftpWithConfig() throws Exception {
cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSftpCloneWithConfigAndPush() throws Exception {
pushTo(cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath()));
}
@Test(expected = TransportException.class)
public void testSshWithConfigWrongKey() throws Exception {
cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey2.getAbsolutePath());
}
@Test
public void testSshWithWrongUserNameInConfig() throws Exception {
// Bug 526778
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"User sombody_else", //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithWrongPortInConfig() throws Exception {
// Bug 526778
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
defaultCloneDir, null, //
"Host localhost", //
"HostName localhost", //
"Port 22", //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshWithAliasInConfig() throws Exception {
// Bug 531118
cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), "", //
"Host localhost", //
"HostName localhost", //
"Port 22", //
"User someone_else", //
"IdentityFile " + privateKey2.getAbsolutePath());
}
@Test
public void testSshWithUnknownCiphersInConfig() throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
}
@Test
public void testSshWithUnknownHostKeyAlgorithmsInConfig()
throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"HostKeyAlgorithms foobar,ssh-rsa,ssh-dss");
}
@Test
public void testSshWithUnknownKexAlgorithmsInConfig()
throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"KexAlgorithms foobar,diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
}
@Test
public void testSshWithMinimalHostKeyAlgorithmsInConfig()
throws Exception {
// Bug 537790
cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"HostKeyAlgorithms ssh-rsa,ssh-dss");
}
@Theory
public void testSshKeys(String keyName) throws Exception {
// JSch fails on ECDSA 384/521 keys. Compare
// https://sourceforge.net/p/jsch/patches/10/
assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory
&& (keyName.startsWith("id_ecdsa_384")
|| keyName.startsWith("id_ecdsa_521"))));
File cloned = new File(getTemporaryDirectory(), "cloned");
String keyFileName = keyName + "_key";
File privateKey = new File(sshDir, keyFileName);
copyTestResource(keyName, privateKey);
File publicKey = new File(sshDir, keyFileName + ".pub");
copyTestResource(keyName + ".pub", publicKey);
server.setTestUserPublicKey(publicKey.toPath());
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
pushTo(provider,
cloneWith("ssh://localhost/doesntmatter", //
cloned, provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey.getAbsolutePath()));
int expectedCalls = keyName.endsWith("testpass") ? 1 : 0;
assertEquals("Unexpected calls to CredentialsProvider", expectedCalls,
provider.getLog().size());
// Should now also work without credentials provider, even if the key
// was encrypted.
cloned = new File(getTemporaryDirectory(), "cloned2");
pushTo(null,
cloneWith("ssh://localhost/doesntmatter", //
cloned, null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey.getAbsolutePath()));
}
}

386
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SshTestBase.java → org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java

@ -40,7 +40,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.transport;
package org.eclipse.jgit.transport.ssh;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -51,6 +51,7 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@ -64,18 +65,39 @@ import java.util.Map;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.ssh.SshTestGitServer;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.junit.After;
import org.junit.Test;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.KeyPair;
public abstract class SshTestBase extends RepositoryTestCase {
/**
* Root class for ssh tests. Sets up the ssh test server. A set of pre-computed
* keys for testing is provided in the bundle and can be used in test cases via
* {@link #copyTestResource(String, File)}. These test key files names have four
* components, separated by a single underscore: "id", the algorithm, the bits
* (if variable), and the password if the private key is encrypted. For instance
* "{@code id_ecdsa_384_testpass}" is an encrypted ECDSA-384 key. The passphrase
* to decrypt is "testpass". The key "{@code id_ecdsa_384}" is the same but
* unencrypted. All keys were generated and encrypted via ssh-keygen. Note that
* DSA and ec25519 have no "bits" component. Available keys are listed in
* {@link SshTestBase#KEY_RESOURCES}.
*/
public abstract class SshTestHarness extends RepositoryTestCase {
protected static final String TEST_USER = "testuser";
@ -85,7 +107,9 @@ public abstract class SshTestBase extends RepositoryTestCase {
protected File privateKey2;
private SshTestGitServer server;
protected File publicKey1;
protected SshTestGitServer server;
private SshSessionFactory factory;
@ -116,11 +140,11 @@ public abstract class SshTestBase extends RepositoryTestCase {
// Create two key pairs. Let's not call them "id_rsa".
privateKey1 = new File(sshDir, "first_key");
privateKey2 = new File(sshDir, "second_key");
createKeyPair(privateKey1);
publicKey1 = createKeyPair(privateKey1);
createKeyPair(privateKey2);
ByteArrayOutputStream publicHostKey = new ByteArrayOutputStream();
// Start a server with our test user and the first key.
server = new SshTestGitServer(TEST_USER, privateKey1.toPath(), db,
server = new SshTestGitServer(TEST_USER, publicKey1.toPath(), db,
createHostKey(publicHostKey));
testPort = server.start();
assertTrue(testPort > 0);
@ -132,7 +156,7 @@ public abstract class SshTestBase extends RepositoryTestCase {
SshSessionFactory.setInstance(factory);
}
private static void createKeyPair(File privateKeyFile) throws Exception {
private static File createKeyPair(File privateKeyFile) throws Exception {
// Found no way to do this with MINA sshd except rolling it all
// ourselves...
JSch jsch = new JSch();
@ -145,6 +169,7 @@ public abstract class SshTestBase extends RepositoryTestCase {
try (OutputStream out = new FileOutputStream(publicKeyFile)) {
pair.writePublicKey(out, TEST_USER);
}
return publicKeyFile;
}
private static byte[] createHostKey(OutputStream publicKey)
@ -159,6 +184,58 @@ public abstract class SshTestBase extends RepositoryTestCase {
}
}
/**
* Creates a new known_hosts file with one entry for the given host and port
* taken from the given public key file.
*
* @param file
* to write the known_hosts file to
* @param host
* for the entry
* @param port
* for the entry
* @param publicKey
* to use
* @return the public-key part of the line
* @throws IOException
*/
protected static String createKnownHostsFile(File file, String host,
int port, File publicKey) throws IOException {
List<String> lines = Files.readAllLines(publicKey.toPath(),
StandardCharsets.UTF_8);
assertEquals("Public key has too many lines", 1, lines.size());
String pubKey = lines.get(0);
// Strip off the comment.
String[] parts = pubKey.split("\\s+");
assertTrue("Unexpected key content",
parts.length == 2 || parts.length == 3);
String keyPart = parts[0] + ' ' + parts[1];
String line = '[' + host + "]:" + port + ' ' + keyPart;
Files.write(file.toPath(), Collections.singletonList(line));
return keyPart;
}
/**
* Checks whether there is a line for the given host and port that also
* matches the given key part in the list of lines.
*
* @param host
* to look for
* @param port
* to look for
* @param keyPart
* to look for
* @param lines
* to look in
* @return {@code true} if found, {@code false} otherwise
*/
protected boolean hasHostKey(String host, int port, String keyPart,
List<String> lines) {
String h = '[' + host + "]:" + port;
return lines.stream()
.anyMatch(l -> l.contains(h) && l.contains(keyPart));
}
@After
public void shutdownServer() throws Exception {
if (server != null) {
@ -178,221 +255,111 @@ public abstract class SshTestBase extends RepositoryTestCase {
protected abstract void installConfig(String... config);
@Test(expected = TransportException.class)
public void testSshCloneWithoutConfig() throws Exception {
cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter", null);
}
@Test
public void testSshCloneWithGlobalIdentity() throws Exception {
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
null,
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshCloneWithDefaultIdentity() throws Exception {
File idRsa = new File(privateKey1.getParentFile(), "id_rsa");
Files.copy(privateKey1.toPath(), idRsa.toPath());
// We expect the session factory to pick up these keys...
cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter", null);
}
@Test
public void testSshCloneWithConfig() throws Exception {
cloneWith("ssh://localhost/doesntmatter", null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshCloneWithConfigEncryptedUnusedKey() throws Exception {
// Copy the encrypted test key from the bundle.
File encryptedKey = new File(sshDir, "id_dsa");
try (InputStream in = SshTestBase.class
.getResourceAsStream("id_dsa_test")) {
Files.copy(in, encryptedKey.toPath());
}
TestCredentialsProvider provider = new TestCredentialsProvider(
"testpass");
cloneWith("ssh://localhost/doesntmatter", provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
assertEquals("CredentialsProvider should not have been called", 0,
provider.getLog().size());
}
@Test(expected = TransportException.class)
public void testSshCloneWithoutKnownHosts() throws Exception {
assertTrue("Could not delete known_hosts", knownHosts.delete());
cloneWith("ssh://localhost/doesntmatter", null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshCloneWithoutKnownHostsWithProvider() throws Exception {
File copiedHosts = new File(knownHosts.getParentFile(),
"copiedKnownHosts");
assertTrue("Failed to rename known_hosts",
knownHosts.renameTo(copiedHosts));
TestCredentialsProvider provider = new TestCredentialsProvider();
cloneWith("ssh://localhost/doesntmatter", provider, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
Map<URIish, List<CredentialItem>> messages = provider.getLog();
assertFalse("Expected user iteraction", messages.isEmpty());
}
@Test
public void testSftpCloneWithConfig() throws Exception {
cloneWith("sftp://localhost/.git", null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test(expected = TransportException.class)
public void testSshCloneWithConfigWrongKey() throws Exception {
cloneWith("ssh://localhost/doesntmatter", null, //
"Host localhost", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey2.getAbsolutePath());
}
@Test
public void testSshCloneWithWrongUserNameInConfig() throws Exception {
// Bug 526778
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
null, //
"Host localhost", //
"HostName localhost", //
"User sombody_else", //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshCloneWithWrongPortInConfig() throws Exception {
// Bug 526778
cloneWith(
"ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter",
null, //
"Host localhost", //
"HostName localhost", //
"Port 22", //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
}
@Test
public void testSshCloneWithAliasInConfig() throws Exception {
// Bug 531118
cloneWith("ssh://git/doesntmatter", null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), "", //
"Host localhost", //
"HostName localhost", //
"Port 22", //
"User someone_else", //
"IdentityFile " + privateKey2.getAbsolutePath());
}
@Test
public void testSshCloneWithUnknownCiphersInConfig() throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
}
@Test
public void testSshCloneWithUnknownHostKeyAlgorithmsInConfig()
throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"HostKeyAlgorithms foobar,ssh-rsa,ssh-dss");
}
@Test
public void testSshCloneWithUnknownKexAlgorithmsInConfig()
throws Exception {
// Bug 535672
cloneWith("ssh://git/doesntmatter", null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"KexAlgorithms foobar,diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
}
@Test
public void testSshCloneWithMinimalHostKeyAlgorithmsInConfig()
throws Exception {
// Bug 537790
cloneWith("ssh://git/doesntmatter", null, //
"Host git", //
"HostName localhost", //
"Port " + testPort, //
"User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath(), //
"HostKeyAlgorithms ssh-rsa,ssh-dss");
/**
* Copies a test data file contained in the test bundle to the given file.
* Equivalent to {@link #copyTestResource(Class, String, File)} with
* {@code SshTestHarness.class} as first parameter.
*
* @param resourceName
* of the test resource to copy
* @param to
* file to copy the resource to
* @throws IOException
* if the resource cannot be copied
*/
protected void copyTestResource(String resourceName, File to)
throws IOException {
copyTestResource(SshTestHarness.class, resourceName, to);
}
private void cloneWith(String uri, CredentialsProvider provider,
/**
* Copies a test data file contained in the test bundle to the given file,
* using {@link Class#getResourceAsStream(String)} to get the test resource.
*
* @param loader
* {@link Class} to use to load the resource
* @param resourceName
* of the test resource to copy
* @param to
* file to copy the resource to
* @throws IOException
* if the resource cannot be copied
*/
protected void copyTestResource(Class<?> loader, String resourceName,
File to) throws IOException {
try (InputStream in = loader.getResourceAsStream(resourceName)) {
Files.copy(in, to.toPath());
}
}
protected File cloneWith(String uri, File to, CredentialsProvider provider,
String... config) throws Exception {
installConfig(config);
File cloned = new File(getTemporaryDirectory(), "cloned");
CloneCommand clone = Git.cloneRepository().setCloneAllBranches(true)
.setDirectory(cloned).setURI(uri);
.setDirectory(to).setURI(uri);
if (provider != null) {
clone.setCredentialsProvider(provider);
}
try (Git git = clone.call()) {
assertNotNull(git.getRepository().resolve("master"));
Repository repo = git.getRepository();
assertNotNull(repo.resolve("master"));
assertNotEquals(db.getWorkTree(),
git.getRepository().getWorkTree());
checkFile(new File(git.getRepository().getWorkTree(), "file.txt"),
"something");
assertTrue(new File(git.getRepository().getWorkTree(), "file.txt")
.exists());
return repo.getWorkTree();
}
}
private static class TestCredentialsProvider extends CredentialsProvider {
protected void pushTo(File localClone) throws Exception {
pushTo(null, localClone);
}
protected void pushTo(CredentialsProvider provider, File localClone)
throws Exception {
RevCommit commit;
File newFile = null;
try (Git git = Git.open(localClone)) {
// Write a new file and modify a file.
Repository local = git.getRepository();
newFile = File.createTempFile("new", "sshtest",
local.getWorkTree());
write(newFile, "something new");
File existingFile = new File(local.getWorkTree(), "file.txt");
write(existingFile, "something else");
git.add().addFilepattern("file.txt")
.addFilepattern(newFile.getName())
.call();
commit = git.commit().setMessage("Local commit").call();
// Push
PushCommand push = git.push().setPushAll();
if (provider != null) {
push.setCredentialsProvider(provider);
}
Iterable<PushResult> results = push.call();
for (PushResult result : results) {
for (RemoteRefUpdate u : result.getRemoteUpdates()) {
assertEquals(
"Could not update " + u.getRemoteName() + ' '
+ u.getMessage(),
RemoteRefUpdate.Status.OK, u.getStatus());
}
}
}
// Now check "master" in the remote repo directly:
assertEquals("Unexpected remote commit", commit, db.resolve("master"));
assertEquals("Unexpected remote commit", commit,
db.resolve(Constants.HEAD));
File remoteFile = new File(db.getWorkTree(), newFile.getName());
assertFalse("File should not exist on remote", remoteFile.exists());
try (Git git = new Git(db)) {
git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD).call();
}
assertTrue("File does not exist on remote", remoteFile.exists());
checkFile(remoteFile, "something new");
}
protected static class TestCredentialsProvider extends CredentialsProvider {
private final List<String> stringStore;
@ -463,4 +430,5 @@ public abstract class SshTestBase extends RepositoryTestCase {
return log;
}
}
}

30
org.eclipse.jgit/src/org/eclipse/jgit/transport/FtpChannel.java

@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.transport;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -201,17 +202,44 @@ public interface FtpChannel {
* @param path
* to delete
* @throws IOException
* if the file does not exist or could otherwise not be deleted
*/
void rm(String path) throws IOException;
/**
* Renames a file on the remote file system.
* Deletes a file on the remote file system. If the file does not exist, no
* exception is thrown.
*
* @param path
* to delete
* @throws IOException
* if the file exist but could not be deleted
*/
default void delete(String path) throws IOException {
try {
rm(path);
} catch (FileNotFoundException e) {
// Ignore; it's OK if the file doesn't exist
} catch (FtpException f) {
if (f.getStatus() == FtpException.NO_SUCH_FILE) {
return;
}
throw f;
}
}
/**
* Renames a file on the remote file system. If {@code to} exists, it is
* replaced by {@code from}. (POSIX rename() semantics)
*
* @param from
* original name of the file
* @param to
* new name of the file
* @throws IOException
* @see <a href=
* "http://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html">stdio.h:
* rename()</a>
*/
void rename(String from, String to) throws IOException;

27
org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java

@ -369,10 +369,37 @@ public class JschSession implements RemoteSession {
@Override
public void rename(String from, String to) throws IOException {
map(() -> {
// Plain FTP rename will fail if "to" exists. Jsch knows about
// the FTP extension "posix-rename@openssh.com", which will
// remove "to" first if it exists.
if (hasPosixRename()) {
ftp.rename(from, to);
} else if (!to.equals(from)) {
// Try to remove "to" first. With git, we typically get this
// when a lock file is moved over the file locked. Note that
// the check for to being equal to from may still fail in
// the general case, but for use with JGit's TransportSftp
// it should be good enough.
delete(to);
ftp.rename(from, to);
}
return null;
});
}
/**
* Determine whether the server has the posix-rename extension.
*
* @return {@code true} if it is supported, {@code false} otherwise
* @see <a href=
* "https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD">OpenSSH
* deviations and extensions to the published SSH protocol</a>
* @see <a href=
* "http://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html">stdio.h:
* rename()</a>
*/
private boolean hasPosixRename() {
return "1".equals(ftp.getExtension("posix-rename@openssh.com")); //$NON-NLS-1$//$NON-NLS-2$
}
}
}

7
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java

@ -272,13 +272,8 @@ public class TransportSftp extends SshTransport implements WalkTransport {
@Override
void deleteFile(String path) throws IOException {
try {
ftp.rm(path);
} catch (FileNotFoundException e) {
return;
ftp.delete(path);
} catch (FtpChannel.FtpException f) {
if (f.getStatus() == FtpChannel.FtpException.NO_SUCH_FILE) {
return;
}
throw new TransportException(MessageFormat.format(
JGitText.get().cannotDeleteObjectsPath, objectsPath,
path, f.getMessage()), f);

Loading…
Cancel
Save