summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/BUILD4
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.classpath11
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.gitignore2
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.project28
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs399
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs66
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs4
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs104
-rw-r--r--org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache.test/BUILD18
-rw-r--r--org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF17
-rw-r--r--org.eclipse.jgit.ssh.apache.test/about.html96
-rw-r--r--org.eclipse.jgit.ssh.apache.test/build.properties5
-rw-r--r--org.eclipse.jgit.ssh.apache.test/plugin.properties2
-rw-r--r--org.eclipse.jgit.ssh.apache.test/pom.xml145
-rw-r--r--org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java83
-rw-r--r--org.eclipse.jgit.ssh.apache/.classpath8
-rw-r--r--org.eclipse.jgit.ssh.apache/.fbprefs125
-rw-r--r--org.eclipse.jgit.ssh.apache/.gitignore2
-rw-r--r--org.eclipse.jgit.ssh.apache/.project34
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs399
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs66
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs4
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs104
-rw-r--r--org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs3
-rw-r--r--org.eclipse.jgit.ssh.apache/BUILD18
-rw-r--r--org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF76
-rw-r--r--org.eclipse.jgit.ssh.apache/about.html96
-rw-r--r--org.eclipse.jgit.ssh.apache/build.properties7
-rw-r--r--org.eclipse.jgit.ssh.apache/plugin.properties2
-rw-r--r--org.eclipse.jgit.ssh.apache/pom.xml206
-rw-r--r--org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties36
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java168
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java114
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java83
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java103
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java275
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java320
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java169
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java718
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java50
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java120
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java87
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java88
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java141
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java74
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java59
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java485
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java436
-rw-r--r--org.eclipse.jgit.test/.classpath1
-rw-r--r--org.eclipse.jgit.test/BUILD28
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.jgit.test/build.properties3
-rw-r--r--org.eclipse.jgit.test/pom.xml12
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096 (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass)0
-rw-r--r--org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub (renamed from org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub)0
-rw-r--r--org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java (renamed from org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java)10
-rw-r--r--org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java (renamed from org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java)0
-rw-r--r--org.eclipse.jgit.test/tests.bzl1
-rw-r--r--org.eclipse.jgit/META-INF/MANIFEST.MF10
-rw-r--r--pom.xml2
101 files changed, 5740 insertions, 9 deletions
diff --git a/lib/BUILD b/lib/BUILD
index 35cb79eb39..047068b180 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -63,6 +63,8 @@ java_library(
visibility = [
"//org.eclipse.jgit.junit:__pkg__",
"//org.eclipse.jgit.test:__pkg__",
+ "//org.eclipse.jgit.ssh.apache:__pkg__",
+ "//org.eclipse.jgit.ssh.apache.test:__pkg__",
],
exports = ["@sshd-core//jar"],
)
@@ -72,6 +74,8 @@ java_library(
visibility = [
"//org.eclipse.jgit.junit:__pkg__",
"//org.eclipse.jgit.test:__pkg__",
+ "//org.eclipse.jgit.ssh.apache:__pkg__",
+ "//org.eclipse.jgit.ssh.apache.test:__pkg__",
],
exports = ["@sshd-sftp//jar"],
)
diff --git a/org.eclipse.jgit.ssh.apache.test/.classpath b/org.eclipse.jgit.ssh.apache.test/.classpath
new file mode 100644
index 0000000000..f08af0a4e9
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="tst">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jgit.ssh.apache.test/.gitignore b/org.eclipse.jgit.ssh.apache.test/.gitignore
new file mode 100644
index 0000000000..934e0e06ff
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/org.eclipse.jgit.ssh.apache.test/.project b/org.eclipse.jgit.ssh.apache.test/.project
new file mode 100644
index 0000000000..0aafb730fb
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.jgit.ssh.apache.test</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..f77db3b723
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Sat Dec 20 21:21:24 CET 2008
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000000..9f733eeea7
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Mon Mar 24 18:55:56 EDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..794592dee1
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,399 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=warning
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=error
+org.eclipse.jdt.core.compiler.problem.deadCode=error
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=error
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..fef3713825
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,66 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_JGit Format
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs
new file mode 100644
index 0000000000..823c0f56ae
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs
@@ -0,0 +1,4 @@
+#Tue Jul 19 20:11:28 CEST 2011
+eclipse.preferences.version=1
+project.repository.kind=bugzilla
+project.repository.url=https\://bugs.eclipse.org/bugs
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs
new file mode 100644
index 0000000000..0cba949fb7
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs
@@ -0,0 +1,3 @@
+#Tue Jul 19 20:11:28 CEST 2011
+commit.comment.template=${task.description} \n\nBug\: ${task.key}
+eclipse.preferences.version=1
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000000..c0030ded71
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,104 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_FIELD=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_DEFAULT_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+changed_execution_env=Error
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+incompatible_api_component_version_report_major_without_breaking_change=Warning
+incompatible_api_component_version_report_minor_without_api_change=Ignore
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000000..82793f2d27
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Jan 14 14:34:32 CST 2010
+eclipse.preferences.version=1
+resolve.requirebundle=false
diff --git a/org.eclipse.jgit.ssh.apache.test/BUILD b/org.eclipse.jgit.ssh.apache.test/BUILD
new file mode 100644
index 0000000000..92ed4de696
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/BUILD
@@ -0,0 +1,18 @@
+load(
+ "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
+ "junit_tests",
+)
+
+junit_tests(
+ name = "sshd_apache",
+ srcs = glob(["tst/**/*.java"]),
+ tags = ["sshd"],
+ deps = [
+ "//org.eclipse.jgit.test:sshd-helpers",
+ "//lib:junit",
+ "//org.eclipse.jgit:jgit",
+ "//lib:sshd-core",
+ "//lib:sshd-sftp",
+ "//org.eclipse.jgit.ssh.apache:ssh-apache",
+ ],
+)
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..c8f53c4c15
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test
+Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test
+Bundle-Version: 5.2.0.qualifier
+Bundle-Vendor: %Provider-Name
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.eclipse.jgit.junit;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.lib;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.transport;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.transport.ssh;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.util;version="[5.2.0,5.3.0)",
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.experimental.theories;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache.test/about.html b/org.eclipse.jgit.ssh.apache.test/about.html
new file mode 100644
index 0000000000..f971af18d0
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/about.html
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Distribution License - Version 1.0</title>
+<style type="text/css">
+ body {
+ size: 8.5in 11.0in;
+ margin: 0.25in 0.5in 0.25in 0.5in;
+ tab-interval: 0.5in;
+ }
+ p {
+ margin-left: auto;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+ p.list {
+ margin-left: 0.5in;
+ margin-top: 0.05em;
+ margin-bottom: 0.05em;
+ }
+ .ubc-name {
+ margin-left: 0.5in;
+ white-space: pre;
+ }
+ </style>
+
+</head>
+
+<body lang="EN-US">
+
+<p><b>Eclipse Distribution License - v 1.0</b></p>
+
+<p>Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. </p>
+
+<p>All rights reserved.</p>
+<p>Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+<ul><li>Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer. </li>
+<li>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. </li>
+<li>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. </li></ul>
+</p>
+<p>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.</p>
+
+<hr>
+<p><b>SHA-1 UbcCheck - MIT</b></p>
+
+<p>Copyright (c) 2017:</p>
+<div class="ubc-name">
+Marc Stevens
+Cryptology Group
+Centrum Wiskunde & Informatica
+P.O. Box 94079, 1090 GB Amsterdam, Netherlands
+marc@marc-stevens.nl
+</div>
+<div class="ubc-name">
+Dan Shumow
+Microsoft Research
+danshu@microsoft.com
+</div>
+<p>Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+</p>
+<ul><li>The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.</li></ul>
+<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</p>
+
+</body>
+
+</html>
diff --git a/org.eclipse.jgit.ssh.apache.test/build.properties b/org.eclipse.jgit.ssh.apache.test/build.properties
new file mode 100644
index 0000000000..9ffa0caf78
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/build.properties
@@ -0,0 +1,5 @@
+source.. = tst/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties
diff --git a/org.eclipse.jgit.ssh.apache.test/plugin.properties b/org.eclipse.jgit.ssh.apache.test/plugin.properties
new file mode 100644
index 0000000000..67c296d9e5
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/plugin.properties
@@ -0,0 +1,2 @@
+plugin_name=JGit Tests for SSH with Apache MINA sshd
+provider_name=Eclipse JGit
diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml
new file mode 100644
index 0000000000..0d5463da6d
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/pom.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit-parent</artifactId>
+ <version>5.2.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
+ <name>JGit - Apache sshd SSH Tests</name>
+
+ <description>
+ JUnit tests for the JGit SSH support based on Apache MINA sshd.
+ </description>
+
+ <properties>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit.junit</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit.test</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ </dependencies>
+
+ <profiles>
+ <!-- Profile provides a property which enables long running tests. -->
+ <profile>
+ <id>test.long</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>-Djgit.test.long=true</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <sourceDirectory>src/</sourceDirectory>
+ <testSourceDirectory>tst/</testSourceDirectory>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+ <includes>
+ <include>**/*Test.java</include>
+ <include>**/*Tests.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
new file mode 100644
index 0000000000..cbbc6386f0
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.sshd;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.ssh.SshTestBase;
+import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
+import org.eclipse.jgit.util.FS;
+import org.junit.experimental.theories.Theories;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ApacheSshTest extends SshTestBase {
+
+ @Override
+ protected SshSessionFactory createSessionFactory() {
+ SshdSessionFactory result = new SshdSessionFactory(new JGitKeyCache());
+ // The home directory is mocked at this point!
+ result.setHomeDirectory(FS.DETECTED.userHome());
+ result.setSshDirectory(sshDir);
+ return result;
+ }
+
+ @Override
+ protected void installConfig(String... config) {
+ File configFile = new File(sshDir, Constants.CONFIG);
+ if (config != null) {
+ try {
+ Files.write(configFile.toPath(), Arrays.asList(config));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/.classpath b/org.eclipse.jgit.ssh.apache/.classpath
new file mode 100644
index 0000000000..110168ffa1
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="resources"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jgit.ssh.apache/.fbprefs b/org.eclipse.jgit.ssh.apache/.fbprefs
new file mode 100644
index 0000000000..81a0767ff6
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.fbprefs
@@ -0,0 +1,125 @@
+#FindBugs User Preferences
+#Mon May 04 16:24:13 PDT 2009
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|true
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorCloneIdiom=CloneIdiom|false
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorDontUseEnum=DontUseEnum|true
+detectorDroppedException=DroppedException|true
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+detectorDumbMethods=DumbMethods|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|true
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|true
+detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorFindOpenStream=FindOpenStream|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindReturnRef=FindReturnRef|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorIncompatMask=IncompatMask|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorInefficientToArray=InefficientToArray|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|false
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorInitializationChain=InitializationChain|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorLazyInit=LazyInit|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorMutableLock=MutableLock|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorNaming=Naming|true
+detectorNumberConstructor=NumberConstructor|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorPublicSemaphores=PublicSemaphores|false
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorStartInConstructor=StartInConstructor|true
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorStringConcatenation=StringConcatenation|true
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorURLProblems=URLProblems|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUnreadFields=UnreadFields|true
+detectorUseObjectEquals=UseObjectEquals|false
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+detectorVarArgsProblems=VarArgsProblems|true
+detectorVolatileUsage=VolatileUsage|true
+detectorWaitInLoop=WaitInLoop|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detector_threshold=2
+effort=default
+excludefilter0=findBugs/FindBugsExcludeFilter.xml
+filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false
+filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL|
+run_at_full_build=true
diff --git a/org.eclipse.jgit.ssh.apache/.gitignore b/org.eclipse.jgit.ssh.apache/.gitignore
new file mode 100644
index 0000000000..934e0e06ff
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/org.eclipse.jgit.ssh.apache/.project b/org.eclipse.jgit.ssh.apache/.project
new file mode 100644
index 0000000000..a7bbd6bafd
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.jgit.ssh.apache</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..66ac15c47c
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Mon Aug 11 16:46:12 PDT 2008
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000000..006e07ede5
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Mon Mar 24 18:55:50 EDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..13c32a6d94
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,399 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=warning
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=error
+org.eclipse.jdt.core.compiler.problem.deadCode=error
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=ignore
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=error
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..fef3713825
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,66 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_JGit Format
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs
new file mode 100644
index 0000000000..823c0f56ae
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs
@@ -0,0 +1,4 @@
+#Tue Jul 19 20:11:28 CEST 2011
+eclipse.preferences.version=1
+project.repository.kind=bugzilla
+project.repository.url=https\://bugs.eclipse.org/bugs
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs
new file mode 100644
index 0000000000..0cba949fb7
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs
@@ -0,0 +1,3 @@
+#Tue Jul 19 20:11:28 CEST 2011
+commit.comment.template=${task.description} \n\nBug\: ${task.key}
+eclipse.preferences.version=1
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000000..c0030ded71
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,104 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_FIELD=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_DEFAULT_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+changed_execution_env=Error
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+incompatible_api_component_version_report_major_without_breaking_change=Warning
+incompatible_api_component_version_report_minor_without_api_change=Ignore
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000000..82793f2d27
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Jan 14 14:34:32 CST 2010
+eclipse.preferences.version=1
+resolve.requirebundle=false
diff --git a/org.eclipse.jgit.ssh.apache/BUILD b/org.eclipse.jgit.ssh.apache/BUILD
new file mode 100644
index 0000000000..d6a145381c
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/BUILD
@@ -0,0 +1,18 @@
+package(default_visibility = ["//visibility:public"])
+
+SRCS = glob(["src/**/*.java"])
+
+RESOURCES = glob(["resources/**"])
+
+java_library(
+ name = "ssh-apache",
+ srcs = SRCS,
+ resource_strip_prefix = "org.eclipse.jgit.ssh.apache/resources",
+ resources = RESOURCES,
+ deps = [
+ "//lib:slf4j-api",
+ "//lib:sshd-core",
+ "//lib:sshd-sftp",
+ "//org.eclipse.jgit:jgit",
+ ],
+)
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..acc81018e8
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -0,0 +1,76 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Automatic-Module-Name: org.eclipse.jgit.ssh.apache
+Bundle-SymbolicName: org.eclipse.jgit.ssh.apache
+Bundle-Vendor: %Provider-Name
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 5.2.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.2.0";x-internal:=true;
+ uses:="org.apache.sshd.client,
+ org.apache.sshd.client.auth,
+ org.apache.sshd.client.auth.keyboard,
+ org.apache.sshd.client.auth.pubkey,
+ org.apache.sshd.client.config.hosts,
+ org.apache.sshd.client.future,
+ org.apache.sshd.client.keyverifier,
+ org.apache.sshd.client.session,
+ org.apache.sshd.common.config.keys,
+ org.apache.sshd.common.io,
+ org.apache.sshd.common.keyprovider,
+ org.apache.sshd.common.signature,
+ org.apache.sshd.common.util.buffer,
+ org.eclipse.jgit.transport",
+ org.eclipse.jgit.transport.sshd;version="5.2.0";
+ uses:="org.apache.sshd.client,
+ org.apache.sshd.client.config.hosts,
+ org.apache.sshd.common.keyprovider,
+ org.apache.sshd.client.keyverifier,
+ org.eclipse.jgit.internal.transport.sshd,
+ org.eclipse.jgit.transport,
+ org.eclipse.jgit.util"
+Import-Package: org.apache.sshd.agent;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.auth;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.auth.password;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.channel;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.config.hosts;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.config.keys;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.future;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.keyverifier;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.session;version="[2.0.0,2.1.0)",
+ org.apache.sshd.client.subsystem.sftp;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.auth;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.channel;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.compression;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.config.keys;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.digest;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.forward;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.future;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.io;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.kex;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.keyprovider;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.mac;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.random;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.session;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.session.helpers;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.signature;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.subsystem.sftp;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.util;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.util.buffer;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.util.io;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.util.logging;version="[2.0.0,2.1.0)",
+ org.apache.sshd.common.util.net;version="[2.0.0,2.1.0)",
+ org.apache.sshd.server.auth;version="[2.0.0,2.1.0)",
+ org.eclipse.jgit.annotations;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.errors;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.nls;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.transport;version="[5.2.0,5.3.0)",
+ org.eclipse.jgit.util;version="[5.2.0,5.3.0)",
+ org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache/about.html b/org.eclipse.jgit.ssh.apache/about.html
new file mode 100644
index 0000000000..f971af18d0
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/about.html
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Distribution License - Version 1.0</title>
+<style type="text/css">
+ body {
+ size: 8.5in 11.0in;
+ margin: 0.25in 0.5in 0.25in 0.5in;
+ tab-interval: 0.5in;
+ }
+ p {
+ margin-left: auto;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+ p.list {
+ margin-left: 0.5in;
+ margin-top: 0.05em;
+ margin-bottom: 0.05em;
+ }
+ .ubc-name {
+ margin-left: 0.5in;
+ white-space: pre;
+ }
+ </style>
+
+</head>
+
+<body lang="EN-US">
+
+<p><b>Eclipse Distribution License - v 1.0</b></p>
+
+<p>Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. </p>
+
+<p>All rights reserved.</p>
+<p>Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+<ul><li>Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer. </li>
+<li>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. </li>
+<li>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. </li></ul>
+</p>
+<p>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.</p>
+
+<hr>
+<p><b>SHA-1 UbcCheck - MIT</b></p>
+
+<p>Copyright (c) 2017:</p>
+<div class="ubc-name">
+Marc Stevens
+Cryptology Group
+Centrum Wiskunde & Informatica
+P.O. Box 94079, 1090 GB Amsterdam, Netherlands
+marc@marc-stevens.nl
+</div>
+<div class="ubc-name">
+Dan Shumow
+Microsoft Research
+danshu@microsoft.com
+</div>
+<p>Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+</p>
+<ul><li>The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.</li></ul>
+<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</p>
+
+</body>
+
+</html>
diff --git a/org.eclipse.jgit.ssh.apache/build.properties b/org.eclipse.jgit.ssh.apache/build.properties
new file mode 100644
index 0000000000..8148271ef3
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/build.properties
@@ -0,0 +1,7 @@
+source.. = src/,\
+ resources/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties,\
+ about.html
diff --git a/org.eclipse.jgit.ssh.apache/plugin.properties b/org.eclipse.jgit.ssh.apache/plugin.properties
new file mode 100644
index 0000000000..8f3540c0f0
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/plugin.properties
@@ -0,0 +1,2 @@
+plugin_name=JGit SSH support based on Apache MINA sshd
+provider_name=Eclipse JGit
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
new file mode 100644
index 0000000000..7c62320a29
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit-parent</artifactId>
+ <version>5.2.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
+ <name>JGit - Apache sshd-based SSH support</name>
+
+ <description>
+ SSH support for JGit based on Apache MINA sshd
+ </description>
+
+ <properties>
+ <translate-qualifier/>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ <version>${apache-sshd-version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-sftp</artifactId>
+ <version>${apache-sshd-version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src/</sourceDirectory>
+
+ <resources>
+ <resource>
+ <directory>.</directory>
+ <includes>
+ <include>plugin.properties</include>
+ <include>about.html</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>resources/</directory>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${bundle-manifest}</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>true</skip><!-- TODO: Enable after the first release -->
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>true</skip><!-- TODO: Enable after the first release -->
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
new file mode 100644
index 0000000000..72bca6a975
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -0,0 +1,36 @@
+authenticationCanceled=Authentication canceled: no password
+closeListenerFailed=Ssh session close listener failed
+configInvalidPath=Invalid path in ssh config key {0}: {1}
+ftpCloseFailed=Closing the SFTP channel failed
+keyEncryptedMsg=Key ''{0}'' is encrypted. Enter the passphrase to decrypt it.
+keyEncryptedPrompt=Passphrase
+keyLoadFailed=Could not load key ''{0}''
+knownHostsCouldNotUpdate=Could not update known hosts file {0}
+knownHostsFileLockedRead=Could not read known hosts file (locked) {0}
+knownHostsFileLockedUpdate=Could not update known hosts file (locked) {0}
+knownHostsFileReadFailed=Failed to read known hosts file {0}
+knownHostsInvalidLine=Known hosts file {0} contains invalid line {1}
+knownHostsInvalidPath=Invalid path for known hosts file {0}
+knownHostsKeyFingerprints=The {0} key''s fingerprints are:
+knownHostsModifiedKeyAcceptPrompt=Accept this key and continue connecting all the same?
+knownHostsModifiedKeyDenyMsg=To resolve this add the correct host key to your known hosts file {0}
+knownHostsModifiedKeyStorePrompt=If so, also store the new key?
+knownHostsModifiedKeyWarning=WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n\
+The connection might be compromised (man-in-the-middle attack).\n\
+It is also possible that the {0} key of the host has just been changed.\n\
+The expected {1} key for host ''{2}'' has the fingerprints:\n\
+{3}\n\
+{4}\n\
+The {0} key actually received has the fingerprints:\n\
+{5}\n\
+{6}
+knownHostsRevokedKeyMsg=Host ''{0}'' sent a key that is marked as revoked in the known hosts file {1}.
+knownHostsUnknownKeyMsg=The authenticity of host ''{0}'' cannot be established.
+knownHostsUnknownKeyPrompt=Accept and store this key, and continue connecting?
+knownHostsUnknownKeyType=Cannot read server key from known hosts file {0}; line {1}
+knownHostsUserAskCreationMsg=File {0} does not exist.
+knownHostsUserAskCreationPrompt=Create file {0} ?
+sessionCloseFailed=Closing the session failed
+sshClosingDown=Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
+sshCommandTimeout={0} timed out after {1} seconds while opening the channel
+sshProcessStillRunning={0} is not yet completed, cannot get exit code \ No newline at end of file
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
new file mode 100644
index 0000000000..dcd17af2ff
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
@@ -0,0 +1,168 @@
+/*
+ * 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.internal.transport.sshd;
+
+import static java.text.MessageFormat.format;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.CancellationException;
+
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.eclipse.jgit.transport.sshd.KeyCache;
+
+/**
+ * A {@link FileKeyPairProvider} that uses an external {@link KeyCache}.
+ */
+public class CachingKeyPairProvider extends FileKeyPairProvider {
+
+ private final KeyCache cache;
+
+ /**
+ * Creates a new {@link CachingKeyPairProvider} using the given
+ * {@link KeyCache}. If the cache is {@code null}, this is a simple
+ * {@link FileKeyPairProvider}.
+ *
+ * @param paths
+ * to load keys from
+ * @param cache
+ * to use, may be {@code null} if no external caching is desired
+ */
+ public CachingKeyPairProvider(List<Path> paths, KeyCache cache) {
+ super(paths);
+ this.cache = cache;
+ }
+
+ @Override
+ protected Iterable<KeyPair> loadKeys(Collection<? extends Path> resources) {
+ if (resources.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return () -> new CancellingKeyPairIterator(resources);
+ }
+
+ @Override
+ protected KeyPair doLoadKey(Path resource)
+ throws IOException, GeneralSecurityException {
+ // By calling doLoadKey(String, Path, FilePasswordProvider) instead of
+ // super.doLoadKey(Path) we can bypass the key caching in
+ // AbstractResourceKeyPairProvider, over which we have no real control.
+ String resourceId = resource.toString();
+ if (cache == null) {
+ return doLoadKey(resourceId, resource, getPasswordFinder());
+ }
+ Throwable t[] = { null };
+ KeyPair key = cache.get(resource, p -> {
+ try {
+ return doLoadKey(resourceId, p, getPasswordFinder());
+ } catch (IOException | GeneralSecurityException e) {
+ t[0] = e;
+ return null;
+ }
+ });
+ if (t[0] != null) {
+ if (t[0] instanceof CancellationException) {
+ throw (CancellationException) t[0];
+ }
+ throw new IOException(
+ format(SshdText.get().keyLoadFailed, resource), t[0]);
+ }
+ return key;
+ }
+
+ private class CancellingKeyPairIterator implements Iterator<KeyPair> {
+
+ private final Iterator<Path> paths;
+
+ private KeyPair nextItem;
+
+ private boolean nextSet;
+
+ public CancellingKeyPairIterator(Collection<? extends Path> resources) {
+ List<Path> copy = new ArrayList<>(resources.size());
+ copy.addAll(resources);
+ paths = copy.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (nextSet) {
+ return nextItem != null;
+ }
+ nextSet = true;
+ while (nextItem == null && paths.hasNext()) {
+ try {
+ nextItem = doLoadKey(paths.next());
+ } catch (CancellationException cancelled) {
+ throw cancelled;
+ } catch (Exception other) {
+ log.warn(other.toString());
+ }
+ }
+ return nextItem != null;
+ }
+
+ @Override
+ public KeyPair next() {
+ if (!nextSet && !hasNext()) {
+ throw new NoSuchElementException();
+ }
+ KeyPair result = nextItem;
+ nextItem = null;
+ nextSet = false;
+ if (result == null) {
+ throw new NoSuchElementException();
+ }
+ return result;
+ }
+
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
new file mode 100644
index 0000000000..2bde7e711d
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -0,0 +1,114 @@
+/*
+ * 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.internal.transport.sshd;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.io.IoSession;
+import org.eclipse.jgit.transport.CredentialsProvider;
+
+/**
+ * A {@link org.apache.sshd.client.session.ClientSession ClientSession} that can
+ * be associated with the {@link HostConfigEntry} the session was created for.
+ * The {@link JGitSshClient} creates such sessions and sets this association.
+ * <p>
+ * Also provides for associating a JGit {@link CredentialsProvider} with a
+ * session.
+ * </p>
+ */
+public class JGitClientSession extends ClientSessionImpl {
+
+ private HostConfigEntry hostConfig;
+
+ private CredentialsProvider credentialsProvider;
+
+ /**
+ * @param manager
+ * @param session
+ * @throws Exception
+ */
+ public JGitClientSession(ClientFactoryManager manager, IoSession session)
+ throws Exception {
+ super(manager, session);
+ }
+
+ /**
+ * Retrieves the {@link HostConfigEntry} this session was created for.
+ *
+ * @return the {@link HostConfigEntry}, or {@code null} if none set
+ */
+ public HostConfigEntry getHostConfigEntry() {
+ return hostConfig;
+ }
+
+ /**
+ * Sets the {@link HostConfigEntry} this session was created for.
+ *
+ * @param hostConfig
+ * the {@link HostConfigEntry}
+ */
+ public void setHostConfigEntry(HostConfigEntry hostConfig) {
+ this.hostConfig = hostConfig;
+ }
+
+ /**
+ * Sets the {@link CredentialsProvider} for this session.
+ *
+ * @param provider
+ * to set
+ */
+ public void setCredentialsProvider(CredentialsProvider provider) {
+ credentialsProvider = provider;
+ }
+
+ /**
+ * Retrieves the {@link CredentialsProvider} set for this session.
+ *
+ * @return the provider, or {@code null} if none is set.
+ */
+ public CredentialsProvider getCredentialsProvider() {
+ return credentialsProvider;
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java
new file mode 100644
index 0000000000..0b3de4ace3
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java
@@ -0,0 +1,83 @@
+/*
+ * 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.internal.transport.sshd;
+
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+import org.apache.sshd.client.auth.UserAuth;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+
+/**
+ * A customized authentication factory for public key user authentication. The
+ * default implementation {@link UserAuthPublicKeyFactory} ends up doing some
+ * crazy stream "magic" that loads too many keys too early.
+ */
+public class JGitPublicKeyAuthFactory extends AbstractUserAuthFactory
+ implements SignatureFactoriesManager {
+
+ /** The singleton {@link JGitPublicKeyAuthFactory}. */
+ public static final JGitPublicKeyAuthFactory INSTANCE = new JGitPublicKeyAuthFactory();
+
+ private JGitPublicKeyAuthFactory() {
+ super(UserAuthPublicKeyFactory.NAME);
+ }
+
+ @Override
+ public UserAuth create() {
+ return new JGitPublicKeyAuthentication(getSignatureFactories());
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return null;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
new file mode 100644
index 0000000000..63b3990b13
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
@@ -0,0 +1,103 @@
+/*
+ * 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.internal.transport.sshd;
+
+import java.util.List;
+
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+
+/**
+ * A specialized public key authentication handler that uses our own
+ * {@link JGitPublicKeyIterator}. The super class creates in
+ * {@link #init(ClientSession, String)} a
+ * {@link org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator}, which
+ * in its constructor does some strange {@link java.util.stream.Stream} "magic"
+ * that ends up loading keys prematurely.
+ */
+public class JGitPublicKeyAuthentication extends UserAuthPublicKey {
+
+ private ClientSession clientSession;
+
+ private String serviceName;
+
+ /**
+ * Creates a new {@link JGitPublicKeyAuthentication}.
+ *
+ * @param factories
+ * signature factories to use
+ */
+ public JGitPublicKeyAuthentication(
+ List<NamedFactory<Signature>> factories) {
+ super(factories);
+ }
+
+ @Override
+ public void init(ClientSession session, String service) throws Exception {
+ // Do *not* call super.init(); it'll create a UserAuthPublicKeyIterator
+ // and that's where things then go wrong. Instead, do the whole
+ // initialization directly here.
+ clientSession = session;
+ serviceName = service;
+ releaseKeys();
+ // Use our own iterator!
+ keys = new JGitPublicKeyIterator(session, this);
+ }
+
+ @Override
+ public ClientSession getClientSession() {
+ return clientSession;
+ }
+
+ @Override
+ public ClientSession getSession() {
+ return clientSession;
+ }
+
+ @Override
+ public String getService() {
+ return serviceName;
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
new file mode 100644
index 0000000000..cda12623d8
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
@@ -0,0 +1,275 @@
+/*
+ * 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.internal.transport.sshd;
+
+import java.io.IOException;
+import java.nio.channels.Channel;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.SshAgentFactory;
+import org.apache.sshd.client.auth.pubkey.AbstractKeyPairIterator;
+import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity;
+import org.apache.sshd.client.auth.pubkey.KeyPairIdentity;
+import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+
+/**
+ * A new iterator over key pairs that we use instead of the default
+ * {@link org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator}, which
+ * in its constructor does some strange {@link java.util.stream.Stream} "magic"
+ * that ends up loading keys prematurely. This class uses plain
+ * {@link Iterator}s instead to avoid that problem. Used in
+ * {@link JGitPublicKeyAuthentication}.
+ *
+ * @see <a href=
+ * "https://issues.apache.org/jira/projects/SSHD/issues/SSHD-860">Upstream
+ * issue SSHD-860</a>
+ */
+public class JGitPublicKeyIterator
+ extends AbstractKeyPairIterator<PublicKeyIdentity> implements Channel {
+
+ // Re: the cause for the problem mentioned above has not been determined.
+ // It looks as if either the Apache code inadvertently calls
+ // GenericUtils.isEmpty() on all streams (which would load the first key
+ // of each stream), or the Java stream implementation does some prefetching.
+ // It's not entirely clear. Using Iterators we have more control over
+ // what happens when.
+
+ private final AtomicBoolean open = new AtomicBoolean(true);
+
+ private SshAgent agent;
+
+ private final List<Iterator<PublicKeyIdentity>> keys = new ArrayList<>(3);
+
+ private final Iterator<Iterator<PublicKeyIdentity>> keyIter;
+
+ private Iterator<PublicKeyIdentity> current;
+
+ private Boolean hasElement;
+
+ /**
+ * Creates a new {@link JGitPublicKeyIterator}.
+ *
+ * @param session
+ * we're trying to authenticate
+ * @param signatureFactories
+ * to use
+ * @throws Exception
+ * if an {@link SshAgentFactory} is configured and getting
+ * identities from the agent fails
+ */
+ public JGitPublicKeyIterator(ClientSession session,
+ SignatureFactoriesManager signatureFactories) throws Exception {
+ super(session);
+ boolean useAgent = true;
+ if (session instanceof JGitClientSession) {
+ HostConfigEntry config = ((JGitClientSession) session)
+ .getHostConfigEntry();
+ useAgent = !config.isIdentitiesOnly();
+ }
+ if (useAgent) {
+ FactoryManager manager = session.getFactoryManager();
+ SshAgentFactory factory = manager == null ? null
+ : manager.getAgentFactory();
+ if (factory != null) {
+ try {
+ agent = factory.createClient(manager);
+ keys.add(new AgentIdentityIterator(agent));
+ } catch (IOException e) {
+ try {
+ closeAgent();
+ } catch (IOException err) {
+ e.addSuppressed(err);
+ }
+ throw e;
+ }
+ }
+ }
+ keys.add(
+ new KeyPairIdentityIterator(session.getRegisteredIdentities(),
+ session, signatureFactories));
+ keys.add(new KeyPairIdentityIterator(session.getKeyPairProvider(),
+ session, signatureFactories));
+ keyIter = keys.iterator();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open.get();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (open.getAndSet(false)) {
+ closeAgent();
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (!isOpen()) {
+ return false;
+ }
+ if (hasElement != null) {
+ return hasElement.booleanValue();
+ }
+ while (current == null || !current.hasNext()) {
+ if (keyIter.hasNext()) {
+ current = keyIter.next();
+ } else {
+ current = null;
+ hasElement = Boolean.FALSE;
+ return false;
+ }
+ }
+ hasElement = Boolean.TRUE;
+ return true;
+ }
+
+ @Override
+ public PublicKeyIdentity next() {
+ if (!isOpen() || hasElement == null && !hasNext()
+ || !hasElement.booleanValue()) {
+ throw new NoSuchElementException();
+ }
+ hasElement = null;
+ PublicKeyIdentity result;
+ try {
+ result = current.next();
+ } catch (NoSuchElementException e) {
+ result = null;
+ }
+ return result;
+ }
+
+ private void closeAgent() throws IOException {
+ if (agent == null) {
+ return;
+ }
+ try {
+ agent.close();
+ } finally {
+ agent = null;
+ }
+ }
+
+ /**
+ * An {@link Iterator} that maps the data obtained from an agent to
+ * {@link PublicKeyIdentity}.
+ */
+ private static class AgentIdentityIterator
+ implements Iterator<PublicKeyIdentity> {
+
+ private final SshAgent agent;
+
+ private final Iterator<? extends Map.Entry<PublicKey, String>> iter;
+
+ public AgentIdentityIterator(SshAgent agent) throws IOException {
+ this.agent = agent;
+ iter = agent == null ? null : agent.getIdentities().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iter != null && iter.hasNext();
+ }
+
+ @Override
+ public PublicKeyIdentity next() {
+ if (iter == null) {
+ throw new NoSuchElementException();
+ }
+ Map.Entry<PublicKey, String> entry = iter.next();
+ return new KeyAgentIdentity(agent, entry.getKey(),
+ entry.getValue());
+ }
+ }
+
+ /**
+ * An {@link Iterator} that maps {@link KeyPair} to
+ * {@link PublicKeyIdentity}.
+ */
+ private static class KeyPairIdentityIterator
+ implements Iterator<PublicKeyIdentity> {
+
+ private final Iterator<KeyPair> keyPairs;
+
+ private final ClientSession session;
+
+ private final SignatureFactoriesManager signatureFactories;
+
+ public KeyPairIdentityIterator(KeyIdentityProvider provider,
+ ClientSession session,
+ SignatureFactoriesManager signatureFactories) {
+ this.session = session;
+ this.signatureFactories = signatureFactories;
+ keyPairs = provider == null ? null : provider.loadKeys().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return keyPairs != null && keyPairs.hasNext();
+ }
+
+ @Override
+ public PublicKeyIdentity next() {
+ if (keyPairs == null) {
+ throw new NoSuchElementException();
+ }
+ KeyPair key = keyPairs.next();
+ return new KeyPairIdentity(signatureFactories, session, key);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
new file mode 100644
index 0000000000..98d4e3e5e5
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
@@ -0,0 +1,320 @@
+/*
+ * 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.internal.transport.sshd;
+
+import static java.text.MessageFormat.format;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.future.DefaultConnectFuture;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.SessionFactory;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoConnectFuture;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.helpers.AbstractSession;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshConstants;
+import org.eclipse.jgit.transport.sshd.KeyCache;
+
+/**
+ * Customized {@link SshClient} for JGit. It creates specialized
+ * {@link JGitClientSession}s that know about the {@link HostConfigEntry} they
+ * were created for, and it loads all KeyPair identities lazily.
+ */
+public class JGitSshClient extends SshClient {
+
+ private KeyCache keyCache;
+
+ private CredentialsProvider credentialsProvider;
+
+ @Override
+ protected SessionFactory createSessionFactory() {
+ // Override the parent's default
+ return new JGitSessionFactory(this);
+ }
+
+ @Override
+ public ConnectFuture connect(HostConfigEntry hostConfig)
+ throws IOException {
+ if (connector == null) {
+ throw new IllegalStateException("SshClient not started."); //$NON-NLS-1$
+ }
+ Objects.requireNonNull(hostConfig, "No host configuration"); //$NON-NLS-1$
+ String host = ValidateUtils.checkNotNullAndNotEmpty(
+ hostConfig.getHostName(), "No target host"); //$NON-NLS-1$
+ int port = hostConfig.getPort();
+ ValidateUtils.checkTrue(port > 0, "Invalid port: %d", port); //$NON-NLS-1$
+ String userName = hostConfig.getUsername();
+ InetSocketAddress address = new InetSocketAddress(host, port);
+ ConnectFuture connectFuture = new DefaultConnectFuture(
+ userName + '@' + address, null);
+ SshFutureListener<IoConnectFuture> listener = createConnectCompletionListener(
+ connectFuture, userName, address, hostConfig);
+ connector.connect(address).addListener(listener);
+ return connectFuture;
+ }
+
+ private SshFutureListener<IoConnectFuture> createConnectCompletionListener(
+ ConnectFuture connectFuture, String username,
+ InetSocketAddress address, HostConfigEntry hostConfig) {
+ return new SshFutureListener<IoConnectFuture>() {
+
+ @Override
+ public void operationComplete(IoConnectFuture future) {
+ if (future.isCanceled()) {
+ connectFuture.cancel();
+ return;
+ }
+ Throwable t = future.getException();
+ if (t != null) {
+ connectFuture.setException(t);
+ return;
+ }
+ IoSession ioSession = future.getSession();
+ try {
+ JGitClientSession session = createSession(ioSession,
+ username, address, hostConfig);
+ connectFuture.setSession(session);
+ } catch (RuntimeException e) {
+ connectFuture.setException(e);
+ ioSession.close(true);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "JGitSshClient$ConnectCompletionListener[" + username //$NON-NLS-1$
+ + '@' + address + ']';
+ }
+ };
+ }
+
+ private JGitClientSession createSession(IoSession ioSession,
+ String username, InetSocketAddress address,
+ HostConfigEntry hostConfig) {
+ AbstractSession rawSession = AbstractSession.getSession(ioSession);
+ if (!(rawSession instanceof JGitClientSession)) {
+ throw new IllegalStateException("Wrong session type: " //$NON-NLS-1$
+ + rawSession.getClass().getCanonicalName());
+ }
+ JGitClientSession session = (JGitClientSession) rawSession;
+ session.setUsername(username);
+ session.setConnectAddress(address);
+ session.setHostConfigEntry(hostConfig);
+ if (session.getCredentialsProvider() == null) {
+ session.setCredentialsProvider(getCredentialsProvider());
+ }
+ FileKeyPairProvider ourConfiguredKeysProvider = null;
+ List<Path> identities = hostConfig.getIdentities().stream()
+ .map(s -> {
+ try {
+ return Paths.get(s);
+ } catch (InvalidPathException e) {
+ log.warn(format(SshdText.get().configInvalidPath,
+ SshConstants.IDENTITY_FILE, s), e);
+ return null;
+ }
+ }).filter(p -> p != null && Files.exists(p))
+ .collect(Collectors.toList());
+ ourConfiguredKeysProvider = new CachingKeyPairProvider(identities,
+ keyCache);
+ ourConfiguredKeysProvider.setPasswordFinder(getFilePasswordProvider());
+ if (hostConfig.isIdentitiesOnly()) {
+ session.setKeyPairProvider(ourConfiguredKeysProvider);
+ } else {
+ KeyPairProvider defaultKeysProvider = getKeyPairProvider();
+ if (defaultKeysProvider instanceof FileKeyPairProvider) {
+ ((FileKeyPairProvider) defaultKeysProvider)
+ .setPasswordFinder(getFilePasswordProvider());
+ }
+ KeyPairProvider combinedProvider = new CombinedKeyPairProvider(
+ ourConfiguredKeysProvider, defaultKeysProvider);
+ session.setKeyPairProvider(combinedProvider);
+ }
+ return session;
+ }
+
+ /**
+ * Set a cache for loaded keys. Newly discovered keys will be added when
+ * IdentityFile host entries from the ssh config file are used during
+ * session authentication.
+ *
+ * @param cache
+ * to use
+ */
+ public void setKeyCache(KeyCache cache) {
+ keyCache = cache;
+ }
+
+ /**
+ * Sets the {@link CredentialsProvider} for this client.
+ *
+ * @param provider
+ * to set
+ */
+ public void setCredentialsProvider(CredentialsProvider provider) {
+ credentialsProvider = provider;
+ }
+
+ /**
+ * Retrieves the {@link CredentialsProvider} set for this client.
+ *
+ * @return the provider, or {@code null} if none is set.
+ */
+ public CredentialsProvider getCredentialsProvider() {
+ return credentialsProvider;
+ }
+
+ /**
+ * A {@link SessionFactory} to create our own specialized
+ * {@link JGitClientSession}s.
+ */
+ private static class JGitSessionFactory extends SessionFactory {
+
+ public JGitSessionFactory(JGitSshClient client) {
+ super(client);
+ }
+
+ @Override
+ protected ClientSessionImpl doCreateSession(IoSession ioSession)
+ throws Exception {
+ return new JGitClientSession(getClient(), ioSession);
+ }
+ }
+
+ /**
+ * A {@link KeyPairProvider} that iterates over the {@link Iterable}s
+ * returned by other {@link KeyPairProvider}s.
+ */
+ private static class CombinedKeyPairProvider implements KeyPairProvider {
+
+ private final List<KeyPairProvider> providers;
+
+ public CombinedKeyPairProvider(KeyPairProvider... providers) {
+ this(Arrays.stream(providers).filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ }
+
+ public CombinedKeyPairProvider(List<KeyPairProvider> providers) {
+ this.providers = providers;
+ }
+
+ @Override
+ public Iterable<String> getKeyTypes() {
+ throw new UnsupportedOperationException(
+ "Should not have been called in a ssh client"); //$NON-NLS-1$
+ }
+
+ @Override
+ public KeyPair loadKey(String type) {
+ throw new UnsupportedOperationException(
+ "Should not have been called in a ssh client"); //$NON-NLS-1$
+ }
+
+ @Override
+ public Iterable<KeyPair> loadKeys() {
+ return () -> new Iterator<KeyPair>() {
+
+ private Iterator<KeyPairProvider> factories = providers.iterator();
+ private Iterator<KeyPair> current;
+
+ private Boolean hasElement;
+
+ @Override
+ public boolean hasNext() {
+ if (hasElement != null) {
+ return hasElement.booleanValue();
+ }
+ while (current == null || !current.hasNext()) {
+ if (factories.hasNext()) {
+ current = factories.next().loadKeys().iterator();
+ } else {
+ current = null;
+ hasElement = Boolean.FALSE;
+ return false;
+ }
+ }
+ hasElement = Boolean.TRUE;
+ return true;
+ }
+
+ @Override
+ public KeyPair next() {
+ if (hasElement == null && !hasNext()
+ || !hasElement.booleanValue()) {
+ throw new NoSuchElementException();
+ }
+ hasElement = null;
+ KeyPair result;
+ try {
+ result = current.next();
+ } catch (NoSuchElementException e) {
+ result = null;
+ }
+ return result;
+ }
+
+ };
+ }
+
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
new file mode 100644
index 0000000000..a96a6962cc
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
@@ -0,0 +1,169 @@
+/*
+ * 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.internal.transport.sshd;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.session.ClientSession;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshConstants;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * A {@link UserInteraction} callback implementation based on a
+ * {@link CredentialsProvider}.
+ */
+public class JGitUserInteraction implements UserInteraction {
+
+ private final CredentialsProvider provider;
+
+ /**
+ * Creates a new {@link JGitUserInteraction} for interactive password input
+ * based on the given {@link CredentialsProvider}.
+ *
+ * @param provider
+ * to use
+ */
+ public JGitUserInteraction(CredentialsProvider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public boolean isInteractionAllowed(ClientSession session) {
+ return provider.isInteractive();
+ }
+
+ @Override
+ public String[] interactive(ClientSession session, String name,
+ String instruction, String lang, String[] prompt, boolean[] echo) {
+ // This is keyboard-interactive authentication
+ List<CredentialItem> items = new ArrayList<>();
+ int numberOfHiddenInputs = 0;
+ for (int i = 0; i < prompt.length; i++) {
+ boolean hidden = i < echo.length && !echo[i];
+ if (hidden) {
+ numberOfHiddenInputs++;
+ }
+ }
+ // RFC 4256 (SSH_MSG_USERAUTH_INFO_REQUEST) says: "The language tag is
+ // deprecated and SHOULD be the empty string." and "[If there are no
+ // prompts] the client SHOULD still display the name and instruction
+ // fields" and "[The] client SHOULD print the name and instruction (if
+ // non-empty)"
+ if (name != null && !name.isEmpty()) {
+ items.add(new CredentialItem.InformationalMessage(name));
+ }
+ if (instruction != null && !instruction.isEmpty()) {
+ items.add(new CredentialItem.InformationalMessage(instruction));
+ }
+ for (int i = 0; i < prompt.length; i++) {
+ boolean hidden = i < echo.length && !echo[i];
+ if (hidden && numberOfHiddenInputs == 1) {
+ // We need to somehow trigger storing the password in the
+ // Eclipse secure storage in EGit. Currently, this is done only
+ // for password fields.
+ items.add(new CredentialItem.Password());
+ // TODO Possibly change EGit to store all hidden strings
+ // (keyed by the URI and the prompt?) so that we don't have to
+ // use this kludge here.
+ } else {
+ items.add(new CredentialItem.StringType(prompt[i], hidden));
+ }
+ }
+ if (items.isEmpty()) {
+ // Huh? No info, no prompts?
+ return prompt; // Is known to have length zero here
+ }
+ URIish uri = toURI(session.getUsername(),
+ (InetSocketAddress) session.getIoSession().getRemoteAddress());
+ if (provider.get(uri, items)) {
+ return items.stream().map(i -> {
+ if (i instanceof CredentialItem.Password) {
+ return new String(((CredentialItem.Password) i).getValue());
+ } else if (i instanceof CredentialItem.StringType) {
+ return ((CredentialItem.StringType) i).getValue();
+ }
+ return null;
+ }).filter(s -> s != null).toArray(String[]::new);
+ }
+ // TODO What to throw to abort the connection/authentication process?
+ // In UserAuthKeyboardInteractive.getUserResponses() it's clear that
+ // returning null is valid and signifies "an error"; we'll try the
+ // next authentication method. But if the user explicitly canceled,
+ // then we don't want to try the next methods...
+ //
+ // Probably not a serious issue with the typical order of public-key,
+ // keyboard-interactive, password.
+ return null;
+ }
+
+ @Override
+ public String getUpdatedPassword(ClientSession session, String prompt,
+ String lang) {
+ // TODO Implement password update in password authentication?
+ return null;
+ }
+
+ /**
+ * Creates a {@link URIish} from the given remote address and user name.
+ *
+ * @param userName
+ * for the uri
+ * @param remote
+ * address of the remote host
+ * @return the uri, with {@link SshConstants#SSH_SCHEME} as scheme
+ */
+ public static URIish toURI(String userName, InetSocketAddress remote) {
+ String host = remote.getHostString();
+ int port = remote.getPort();
+ return new URIish() //
+ .setScheme(SshConstants.SSH_SCHEME) //
+ .setHost(host) //
+ .setPort(port) //
+ .setUser(userName);
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
new file mode 100644
index 0000000000..a20ee6bb84
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
@@ -0,0 +1,718 @@
+/*
+ * 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.internal.transport.sshd;
+
+import static java.text.MessageFormat.format;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.config.hosts.KnownHostEntry;
+import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier;
+import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier.HostEntryPair;
+import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
+import org.apache.sshd.client.session.ClientSession;
+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.digest.BuiltinDigests;
+import org.apache.sshd.common.util.io.ModifiableFileWatcher;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.eclipse.jgit.internal.storage.file.LockFile;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshConstants;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.sshd.JGitHostConfigEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A sever host key verifier that honors the {@code StrictHostKeyChecking} and
+ * {@code UserKnownHostsFile} values from the ssh configuration.
+ * <p>
+ * The verifier can be given default known_hosts files in the constructor, which
+ * will be used if the ssh config does not specify a {@code UserKnownHostsFile}.
+ * If the ssh config <em>does</em> set {@code UserKnownHostsFile}, the verifier
+ * uses the given files in the order given. Non-existing or unreadable files are
+ * ignored.
+ * <p>
+ * {@code StrictHostKeyChecking} accepts the following values:
+ * </p>
+ * <dl>
+ * <dt>ask</dt>
+ * <dd>Ask the user whether new or changed keys shall be accepted and be added
+ * to the known_hosts file.</dd>
+ * <dt>yes/true</dt>
+ * <dd>Accept only keys listed in the known_hosts file.</dd>
+ * <dt>no/false</dt>
+ * <dd>Silently accept all new or changed keys, add new keys to the known_hosts
+ * file.</dd>
+ * <dt>accept-new</dt>
+ * <dd>Silently accept keys for new hosts and add them to the known_hosts
+ * file.</dd>
+ * </dl>
+ * <p>
+ * If {@code StrictHostKeyChecking} is not set, or set to any other value, the
+ * default value <b>ask</b> is active.
+ * </p>
+ * <p>
+ * This implementation relies on the {@link ClientSession} being a
+ * {@link JGitClientSession}. By default Apache MINA sshd does not forward the
+ * config file host entry to the session, so it would be unknown here which
+ * entry it was and what setting of {@code StrictHostKeyChecking} should be
+ * used. If used with some other session type, the implementation assumes
+ * "<b>ask</b>".
+ * <p>
+ * <p>
+ * Asking the user is done via a {@link CredentialsProvider} obtained from the
+ * session. If none is set, the implementation falls back to strict host key
+ * checking ("<b>yes</b>").
+ * </p>
+ * <p>
+ * Note that adding a key to the known hosts file may create the file. You can
+ * specify in the constructor whether the user shall be asked about that, too.
+ * If the the user declines updating the file, but the key was otherwise
+ * accepted (user confirmed for "<b>ask</b>", or "no" or "accept-new" are
+ * active), the key is accepted for this session only.
+ * </p>
+ * <p>
+ * If several known hosts files are specified, a new key is always added to the
+ * first file (even if it doesn't exist yet; see the note about file creation
+ * above).
+ * </p>
+ *
+ * @see <a href="http://man.openbsd.org/OpenBSD-current/man5/ssh_config.5">man
+ * ssh-config</a>
+ */
+public class OpenSshServerKeyVerifier implements ServerKeyVerifier {
+
+ // TODO: GlobalKnownHostsFile? May need some kind of LRU caching; these
+ // files may be large!
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(OpenSshServerKeyVerifier.class);
+
+ /** Can be used to mark revoked known host lines. */
+ private static final String MARKER_REVOKED = "revoked"; //$NON-NLS-1$
+
+ private final boolean askAboutNewFile;
+
+ private final Map<Path, HostKeyFile> knownHostsFiles = new ConcurrentHashMap<>();
+
+ private final List<HostKeyFile> defaultFiles = new ArrayList<>();
+
+ private enum ModifiedKeyHandling {
+ DENY, ALLOW, ALLOW_AND_STORE
+ }
+
+ /**
+ * Creates a new {@link OpenSshServerKeyVerifier}.
+ *
+ * @param askAboutNewFile
+ * whether to ask the user, if possible, about creating a new
+ * non-existing known_hosts file
+ * @param defaultFiles
+ * typically ~/.ssh/known_hosts and ~/.ssh/known_hosts2. May be
+ * empty or {@code null}, in which case no default files are
+ * installed. The files need not exist.
+ */
+ public OpenSshServerKeyVerifier(boolean askAboutNewFile, List<File> defaultFiles) {
+ if (defaultFiles != null) {
+ for (File file : defaultFiles) {
+ Path p = file.toPath();
+ HostKeyFile newFile = new HostKeyFile(p);
+ knownHostsFiles.put(p, newFile);
+ this.defaultFiles.add(newFile);
+ }
+ }
+ this.askAboutNewFile = askAboutNewFile;
+ }
+
+ @Override
+ public boolean verifyServerKey(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey) {
+ List<HostKeyFile> filesToUse = defaultFiles;
+ if (clientSession instanceof JGitClientSession) {
+ HostConfigEntry entry = ((JGitClientSession) clientSession)
+ .getHostConfigEntry();
+ if (entry instanceof JGitHostConfigEntry) {
+ // Always true!
+ List<HostKeyFile> userFiles = addUserHostKeyFiles(
+ ((JGitHostConfigEntry) entry).getMultiValuedOptions()
+ .get(SshConstants.USER_KNOWN_HOSTS_FILE));
+ if (!userFiles.isEmpty()) {
+ filesToUse = userFiles;
+ }
+ }
+ }
+ AskUser ask = new AskUser();
+ HostEntryPair[] modified = { null };
+ Path path = null;
+ HostKeyHelper helper = new HostKeyHelper();
+ for (HostKeyFile file : filesToUse) {
+ try {
+ if (find(clientSession, remoteAddress, serverKey, file.get(),
+ modified, helper)) {
+ return true;
+ }
+ } catch (RevokedKeyException e) {
+ ask.revokedKey(clientSession, remoteAddress, serverKey,
+ file.getPath());
+ return false;
+ }
+ if (path == null && modified[0] != null) {
+ // Remember the file in which we might need to update the
+ // entry
+ path = file.getPath();
+ }
+ }
+ if (modified[0] != null) {
+ // We found an entry, but with a different key
+ ModifiedKeyHandling toDo = ask.acceptModifiedServerKey(
+ clientSession, remoteAddress, modified[0].getServerKey(),
+ serverKey, path);
+ if (toDo == ModifiedKeyHandling.ALLOW_AND_STORE) {
+ try {
+ updateModifiedServerKey(clientSession, remoteAddress,
+ serverKey, modified[0], path, helper);
+ knownHostsFiles.get(path).resetReloadAttributes();
+ } catch (IOException e) {
+ LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate,
+ path));
+ }
+ }
+ if (toDo == ModifiedKeyHandling.DENY) {
+ return false;
+ }
+ // TODO: OpenSsh disables password and keyboard-interactive
+ // authentication in this case. Also agent and local port forwarding
+ // are switched off. (Plus a few other things such as X11 forwarding
+ // that are of no interest to a git client.)
+ return true;
+ } else if (ask.acceptUnknownKey(clientSession, remoteAddress,
+ serverKey)) {
+ if (!filesToUse.isEmpty()) {
+ HostKeyFile toUpdate = filesToUse.get(0);
+ path = toUpdate.getPath();
+ try {
+ updateKnownHostsFile(clientSession, remoteAddress,
+ serverKey, path, helper);
+ toUpdate.resetReloadAttributes();
+ } catch (IOException e) {
+ LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate,
+ path));
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static class RevokedKeyException extends Exception {
+ private static final long serialVersionUID = 1L;
+ }
+
+ private boolean find(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey,
+ List<HostEntryPair> entries, HostEntryPair[] modified,
+ HostKeyHelper helper) throws RevokedKeyException {
+ Collection<SshdSocketAddress> candidates = helper
+ .resolveHostNetworkIdentities(clientSession, remoteAddress);
+ for (HostEntryPair current : entries) {
+ KnownHostEntry entry = current.getHostEntry();
+ for (SshdSocketAddress host : candidates) {
+ if (entry.isHostMatch(host.getHostName(), host.getPort())) {
+ boolean isRevoked = MARKER_REVOKED
+ .equals(entry.getMarker());
+ if (KeyUtils.compareKeys(serverKey,
+ current.getServerKey())) {
+ // Exact match
+ if (isRevoked) {
+ throw new RevokedKeyException();
+ }
+ modified[0] = null;
+ return true;
+ } else if (!isRevoked) {
+ // Server sent a different key
+ modified[0] = current;
+ // Keep going -- maybe there's another entry for this
+ // host
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private List<HostKeyFile> addUserHostKeyFiles(List<String> fileNames) {
+ if (fileNames == null || fileNames.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<HostKeyFile> userFiles = new ArrayList<>();
+ for (String name : fileNames) {
+ try {
+ Path path = Paths.get(name);
+ HostKeyFile file = knownHostsFiles.computeIfAbsent(path,
+ p -> new HostKeyFile(path));
+ userFiles.add(file);
+ } catch (InvalidPathException e) {
+ LOG.warn(format(SshdText.get().knownHostsInvalidPath,
+ name));
+ }
+ }
+ return userFiles;
+ }
+
+ private void updateKnownHostsFile(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey, Path path,
+ HostKeyHelper updater)
+ throws IOException {
+ KnownHostEntry entry = updater.prepareKnownHostEntry(clientSession,
+ remoteAddress, serverKey);
+ if (entry == null) {
+ return;
+ }
+ if (!Files.exists(path)) {
+ if (askAboutNewFile) {
+ CredentialsProvider provider = getCredentialsProvider(
+ clientSession);
+ if (provider == null) {
+ // We can't ask, so don't create the file
+ return;
+ }
+ URIish uri = new URIish().setPath(path.toString());
+ if (!askUser(provider, uri, //
+ format(SshdText.get().knownHostsUserAskCreationPrompt,
+ path), //
+ format(SshdText.get().knownHostsUserAskCreationMsg,
+ path))) {
+ return;
+ }
+ }
+ }
+ LockFile lock = new LockFile(path.toFile());
+ if (lock.lockForAppend()) {
+ try {
+ try (BufferedWriter writer = new BufferedWriter(
+ new OutputStreamWriter(lock.getOutputStream(),
+ StandardCharsets.UTF_8))) {
+ writer.newLine();
+ writer.write(entry.getConfigLine());
+ writer.newLine();
+ }
+ lock.commit();
+ } catch (IOException e) {
+ lock.unlock();
+ throw e;
+ }
+ } else {
+ LOG.warn(format(SshdText.get().knownHostsFileLockedUpdate,
+ path));
+ }
+ }
+
+ private void updateModifiedServerKey(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey,
+ HostEntryPair entry, Path path, HostKeyHelper helper)
+ throws IOException {
+ KnownHostEntry hostEntry = entry.getHostEntry();
+ String oldLine = hostEntry.getConfigLine();
+ String newLine = helper.prepareModifiedServerKeyLine(clientSession,
+ remoteAddress, hostEntry, oldLine, entry.getServerKey(),
+ serverKey);
+ if (newLine == null || newLine.isEmpty()) {
+ return;
+ }
+ if (oldLine == null || oldLine.isEmpty() || newLine.equals(oldLine)) {
+ // Shouldn't happen.
+ return;
+ }
+ LockFile lock = new LockFile(path.toFile());
+ if (lock.lock()) {
+ try {
+ try (BufferedWriter writer = new BufferedWriter(
+ new OutputStreamWriter(lock.getOutputStream(),
+ StandardCharsets.UTF_8));
+ BufferedReader reader = Files.newBufferedReader(path,
+ StandardCharsets.UTF_8)) {
+ boolean done = false;
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String toWrite = line;
+ if (!done) {
+ int pos = line.indexOf('#');
+ String toTest = pos < 0 ? line
+ : line.substring(0, pos);
+ if (toTest.trim().equals(oldLine)) {
+ toWrite = newLine;
+ done = true;
+ }
+ }
+ writer.write(toWrite);
+ writer.newLine();
+ }
+ }
+ lock.commit();
+ } catch (IOException e) {
+ lock.unlock();
+ throw e;
+ }
+ } else {
+ LOG.warn(format(SshdText.get().knownHostsFileLockedUpdate,
+ path));
+ }
+ }
+
+ private static CredentialsProvider getCredentialsProvider(
+ ClientSession session) {
+ if (session instanceof JGitClientSession) {
+ return ((JGitClientSession) session).getCredentialsProvider();
+ }
+ return null;
+ }
+
+ private static boolean askUser(CredentialsProvider provider, URIish uri,
+ String prompt, String... messages) {
+ List<CredentialItem> items = new ArrayList<>(messages.length + 1);
+ for (String message : messages) {
+ items.add(new CredentialItem.InformationalMessage(message));
+ }
+ if (prompt != null) {
+ CredentialItem.YesNoType answer = new CredentialItem.YesNoType(
+ prompt);
+ items.add(answer);
+ return provider.get(uri, items) && answer.getValue();
+ } else {
+ return provider.get(uri, items);
+ }
+ }
+
+ private static class AskUser {
+
+ private enum Check {
+ ASK, DENY, ALLOW;
+ }
+
+ @SuppressWarnings("nls")
+ private Check checkMode(ClientSession session,
+ SocketAddress remoteAddress, boolean changed) {
+ if (!(remoteAddress instanceof InetSocketAddress)) {
+ return Check.DENY;
+ }
+ if (session instanceof JGitClientSession) {
+ HostConfigEntry entry = ((JGitClientSession) session)
+ .getHostConfigEntry();
+ String value = entry.getProperty(
+ SshConstants.STRICT_HOST_KEY_CHECKING, "ask");
+ switch (value.toLowerCase(Locale.ROOT)) {
+ case SshConstants.YES:
+ case SshConstants.ON:
+ return Check.DENY;
+ case SshConstants.NO:
+ case SshConstants.OFF:
+ return Check.ALLOW;
+ case "accept-new":
+ return changed ? Check.DENY : Check.ALLOW;
+ default:
+ break;
+ }
+ }
+ if (getCredentialsProvider(session) == null) {
+ // This is called only for new, unknown hosts. If we have no way
+ // to interact with the user, the fallback mode is to deny the
+ // key.
+ return Check.DENY;
+ }
+ return Check.ASK;
+ }
+
+ public void revokedKey(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey, Path path) {
+ CredentialsProvider provider = getCredentialsProvider(
+ clientSession);
+ if (provider == null) {
+ return;
+ }
+ InetSocketAddress remote = (InetSocketAddress) remoteAddress;
+ URIish uri = JGitUserInteraction.toURI(clientSession.getUsername(),
+ remote);
+ String sha256 = KeyUtils.getFingerPrint(BuiltinDigests.sha256,
+ serverKey);
+ String md5 = KeyUtils.getFingerPrint(BuiltinDigests.md5, serverKey);
+ String keyAlgorithm = serverKey.getAlgorithm();
+ askUser(provider, uri, null, //
+ format(SshdText.get().knownHostsRevokedKeyMsg,
+ remote.getHostString(), path),
+ format(SshdText.get().knownHostsKeyFingerprints,
+ keyAlgorithm),
+ md5, sha256);
+ }
+
+ public boolean acceptUnknownKey(ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey serverKey) {
+ Check check = checkMode(clientSession, remoteAddress, false);
+ if (check != Check.ASK) {
+ return check == Check.ALLOW;
+ }
+ CredentialsProvider provider = getCredentialsProvider(
+ clientSession);
+ InetSocketAddress remote = (InetSocketAddress) remoteAddress;
+ // Ask the user
+ String sha256 = KeyUtils.getFingerPrint(BuiltinDigests.sha256,
+ serverKey);
+ String md5 = KeyUtils.getFingerPrint(BuiltinDigests.md5, serverKey);
+ String keyAlgorithm = serverKey.getAlgorithm();
+ String remoteHost = remote.getHostString();
+ URIish uri = JGitUserInteraction.toURI(clientSession.getUsername(),
+ remote);
+ String prompt = SshdText.get().knownHostsUnknownKeyPrompt;
+ return askUser(provider, uri, prompt, //
+ format(SshdText.get().knownHostsUnknownKeyMsg,
+ remoteHost),
+ format(SshdText.get().knownHostsKeyFingerprints,
+ keyAlgorithm),
+ md5, sha256);
+ }
+
+ public ModifiedKeyHandling acceptModifiedServerKey(
+ ClientSession clientSession,
+ SocketAddress remoteAddress, PublicKey expected,
+ PublicKey actual, Path path) {
+ Check check = checkMode(clientSession, remoteAddress, true);
+ if (check == Check.ALLOW) {
+ // Never auto-store on CHECK.ALLOW
+ return ModifiedKeyHandling.ALLOW;
+ }
+ InetSocketAddress remote = (InetSocketAddress) remoteAddress;
+ String keyAlgorithm = actual.getAlgorithm();
+ String remoteHost = remote.getHostString();
+ URIish uri = JGitUserInteraction.toURI(clientSession.getUsername(),
+ remote);
+ List<String> messages = new ArrayList<>();
+ String warning = format(
+ SshdText.get().knownHostsModifiedKeyWarning,
+ keyAlgorithm, expected.getAlgorithm(), remoteHost,
+ KeyUtils.getFingerPrint(BuiltinDigests.md5, expected),
+ KeyUtils.getFingerPrint(BuiltinDigests.sha256, expected),
+ KeyUtils.getFingerPrint(BuiltinDigests.md5, actual),
+ KeyUtils.getFingerPrint(BuiltinDigests.sha256, actual));
+ for (String line : warning.split("\n")) { //$NON-NLS-1$
+ messages.add(line);
+ }
+
+ CredentialsProvider provider = getCredentialsProvider(
+ clientSession);
+ if (check == Check.DENY) {
+ if (provider != null) {
+ messages.add(format(
+ SshdText.get().knownHostsModifiedKeyDenyMsg, path));
+ askUser(provider, uri, null,
+ messages.toArray(new String[0]));
+ }
+ return ModifiedKeyHandling.DENY;
+ }
+ // ASK -- two questions: procceed? and store?
+ List<CredentialItem> items = new ArrayList<>(messages.size() + 2);
+ for (String message : messages) {
+ items.add(new CredentialItem.InformationalMessage(message));
+ }
+ CredentialItem.YesNoType proceed = new CredentialItem.YesNoType(
+ SshdText.get().knownHostsModifiedKeyAcceptPrompt);
+ CredentialItem.YesNoType store = new CredentialItem.YesNoType(
+ SshdText.get().knownHostsModifiedKeyStorePrompt);
+ items.add(proceed);
+ items.add(store);
+ if (provider.get(uri, items) && proceed.getValue()) {
+ return store.getValue() ? ModifiedKeyHandling.ALLOW_AND_STORE
+ : ModifiedKeyHandling.ALLOW;
+ }
+ return ModifiedKeyHandling.DENY;
+ }
+
+ }
+
+ private static class HostKeyFile extends ModifiableFileWatcher
+ implements Supplier<List<HostEntryPair>> {
+
+ private List<HostEntryPair> entries = Collections.emptyList();
+
+ public HostKeyFile(Path path) {
+ super(path);
+ }
+
+ @Override
+ public List<HostEntryPair> get() {
+ Path path = getPath();
+ try {
+ if (checkReloadRequired()) {
+ if (!Files.exists(path)) {
+ // Has disappeared.
+ resetReloadAttributes();
+ return Collections.emptyList();
+ }
+ LockFile lock = new LockFile(path.toFile());
+ if (lock.lock()) {
+ try {
+ entries = reload(getPath());
+ } finally {
+ lock.unlock();
+ }
+ } else {
+ LOG.warn(format(SshdText.get().knownHostsFileLockedRead,
+ path));
+ }
+ }
+ } catch (IOException e) {
+ LOG.warn(format(SshdText.get().knownHostsFileReadFailed, path));
+ }
+ return Collections.unmodifiableList(entries);
+ }
+
+ private List<HostEntryPair> reload(Path path) throws IOException {
+ try {
+ List<KnownHostEntry> rawEntries = KnownHostEntry
+ .readKnownHostEntries(path);
+ updateReloadAttributes();
+ if (rawEntries == null || rawEntries.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<HostEntryPair> newEntries = new LinkedList<>();
+ for (KnownHostEntry entry : rawEntries) {
+ AuthorizedKeyEntry keyPart = entry.getKeyEntry();
+ if (keyPart == null) {
+ continue;
+ }
+ try {
+ PublicKey serverKey = keyPart.resolvePublicKey(
+ PublicKeyEntryResolver.IGNORING);
+ if (serverKey == null) {
+ LOG.warn(format(
+ SshdText.get().knownHostsUnknownKeyType,
+ getPath(), entry.getConfigLine()));
+ } else {
+ newEntries.add(new HostEntryPair(entry, serverKey));
+ }
+ } catch (GeneralSecurityException e) {
+ LOG.warn(format(SshdText.get().knownHostsInvalidLine,
+ getPath(), entry.getConfigLine()));
+ }
+ }
+ return newEntries;
+ } catch (FileNotFoundException e) {
+ resetReloadAttributes();
+ return Collections.emptyList();
+ }
+ }
+ }
+
+ // The stuff below is just a hack to avoid having to copy a lot of code from
+ // KnownHostsServerKeyVerifier
+
+ private static class HostKeyHelper extends KnownHostsServerKeyVerifier {
+
+ public HostKeyHelper() {
+ // These two arguments will never be used in any way.
+ super((c, r, s) -> false, new File(".").toPath()); //$NON-NLS-1$
+ }
+
+ @Override
+ protected KnownHostEntry prepareKnownHostEntry(
+ ClientSession clientSession, SocketAddress remoteAddress,
+ PublicKey serverKey) throws IOException {
+ // Make this method accessible
+ try {
+ return super.prepareKnownHostEntry(clientSession, remoteAddress,
+ serverKey);
+ } catch (Exception e) {
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ protected String prepareModifiedServerKeyLine(
+ ClientSession clientSession, SocketAddress remoteAddress,
+ KnownHostEntry entry, String curLine, PublicKey expected,
+ PublicKey actual) throws IOException {
+ // Make this method accessible
+ try {
+ return super.prepareModifiedServerKeyLine(clientSession,
+ remoteAddress, entry, curLine, expected, actual);
+ } catch (Exception e) {
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ protected Collection<SshdSocketAddress> resolveHostNetworkIdentities(
+ ClientSession clientSession, SocketAddress remoteAddress) {
+ // Make this method accessible
+ return super.resolveHostNetworkIdentities(clientSession,
+ remoteAddress);
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
new file mode 100644
index 0000000000..7f08f72f25
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -0,0 +1,50 @@
+package org.eclipse.jgit.internal.transport.sshd;
+
+import org.eclipse.jgit.nls.NLS;
+import org.eclipse.jgit.nls.TranslationBundle;
+
+/**
+ * Externalized text messages for localization.
+ */
+public final class SshdText extends TranslationBundle {
+
+ /**
+ * Get an instance of this translation bundle.
+ *
+ * @return an instance of this translation bundle
+ */
+ public static SshdText get() {
+ return NLS.getBundleFor(SshdText.class);
+ }
+
+ // @formatter:off
+ /***/ public String authenticationCanceled;
+ /***/ public String closeListenerFailed;
+ /***/ public String configInvalidPath;
+ /***/ public String ftpCloseFailed;
+ /***/ public String keyEncryptedMsg;
+ /***/ public String keyEncryptedPrompt;
+ /***/ public String keyLoadFailed;
+ /***/ public String knownHostsCouldNotUpdate;
+ /***/ public String knownHostsFileLockedRead;
+ /***/ public String knownHostsFileLockedUpdate;
+ /***/ public String knownHostsFileReadFailed;
+ /***/ public String knownHostsInvalidLine;
+ /***/ public String knownHostsInvalidPath;
+ /***/ public String knownHostsKeyFingerprints;
+ /***/ public String knownHostsModifiedKeyAcceptPrompt;
+ /***/ public String knownHostsModifiedKeyDenyMsg;
+ /***/ public String knownHostsModifiedKeyStorePrompt;
+ /***/ public String knownHostsModifiedKeyWarning;
+ /***/ public String knownHostsRevokedKeyMsg;
+ /***/ public String knownHostsUnknownKeyMsg;
+ /***/ public String knownHostsUnknownKeyPrompt;
+ /***/ public String knownHostsUnknownKeyType;
+ /***/ public String knownHostsUserAskCreationMsg;
+ /***/ public String knownHostsUserAskCreationPrompt;
+ /***/ public String sessionCloseFailed;
+ /***/ public String sshClosingDown;
+ /***/ public String sshCommandTimeout;
+ /***/ public String sshProcessStillRunning;
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
new file mode 100644
index 0000000000..5a0bd7fdc8
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
@@ -0,0 +1,120 @@
+/*
+ * 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.sshd;
+
+import static java.text.MessageFormat.format;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.eclipse.jgit.internal.transport.sshd.SshdText;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * A {@link FilePasswordProvider} based on a {@link CredentialsProvider}.
+ *
+ * @since 5.2
+ */
+public class IdentityPasswordProvider implements FilePasswordProvider {
+
+ private CredentialsProvider provider;
+
+ /**
+ * Creates a new {@link IdentityPasswordProvider} to get the passphrase for
+ * an encrypted identity.
+ *
+ * @param provider
+ * to use
+ */
+ public IdentityPasswordProvider(CredentialsProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * Creates a {@link URIish} from a given string. The
+ * {@link CredentialsProvider} uses uris as resource identifications.
+ *
+ * @param resourceKey
+ * to convert
+ * @return the uri
+ */
+ protected URIish toUri(String resourceKey) {
+ try {
+ return new URIish(resourceKey);
+ } catch (URISyntaxException e) {
+ return new URIish().setPath(resourceKey); // Doesn't check!!
+ }
+ }
+
+ @Override
+ public String getPassword(String resourceKey) throws IOException {
+ if (provider == null) {
+ return null;
+ }
+ URIish file = toUri(resourceKey);
+ List<CredentialItem> items = new ArrayList<>(2);
+ items.add(new CredentialItem.InformationalMessage(
+ format(SshdText.get().keyEncryptedMsg, resourceKey)));
+ CredentialItem.Password password = new CredentialItem.Password(
+ SshdText.get().keyEncryptedPrompt);
+ items.add(password);
+ try {
+ provider.get(file, items);
+ char[] pass = password.getValue();
+ if (pass == null) {
+ throw new CancellationException(
+ SshdText.get().authenticationCanceled);
+ }
+ return new String(pass);
+ } finally {
+ password.clear();
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java
new file mode 100644
index 0000000000..6bffa2e3ee
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java
@@ -0,0 +1,87 @@
+/*
+ * 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.sshd;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * A {@link HostConfigEntry} that provides access to the multi-valued keys as
+ * lists of strings. The super class treats them as single strings containing
+ * comma-separated lists.
+ *
+ * @since 5.2
+ */
+public class JGitHostConfigEntry extends HostConfigEntry {
+
+ private Map<String, List<String>> multiValuedOptions;
+
+ /**
+ * Sets the multi-valued options.
+ *
+ * @param options
+ * to set, may be {@code null} to set an empty map
+ */
+ public void setMultiValuedOptions(Map<String, List<String>> options) {
+ multiValuedOptions = options;
+ }
+
+ /**
+ * Retrieves all multi-valued options.
+ *
+ * @return an unmodifiable map
+ */
+ @NonNull
+ public Map<String, List<String>> getMultiValuedOptions() {
+ Map<String, List<String>> options = multiValuedOptions;
+ if (options == null) {
+ return Collections.emptyMap();
+ }
+ return Collections.unmodifiableMap(options);
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java
new file mode 100644
index 0000000000..52325c6780
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java
@@ -0,0 +1,88 @@
+/*
+ * 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.sshd;
+
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+
+import javax.security.auth.DestroyFailedException;
+
+/**
+ * A simple {@link KeyCache}. JGit uses one such cache in its
+ * {@link SshdSessionFactory} to avoid loading keys multiple times.
+ *
+ * @since 5.2
+ */
+public class JGitKeyCache implements KeyCache {
+
+ private AtomicReference<Map<Path, KeyPair>> cache = new AtomicReference<>(
+ new ConcurrentHashMap<>());
+
+ @Override
+ public KeyPair get(Path path,
+ Function<? super Path, ? extends KeyPair> loader) {
+ return cache.get().computeIfAbsent(path, loader);
+ }
+
+ @Override
+ public void close() {
+ Map<Path, KeyPair> map = cache.getAndSet(null);
+ if (map == null) {
+ return;
+ }
+ for (KeyPair k : map.values()) {
+ PrivateKey p = k.getPrivate();
+ try {
+ p.destroy();
+ } catch (DestroyFailedException e) {
+ // Ignore here. We did our best.
+ }
+ }
+ map.clear();
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java
new file mode 100644
index 0000000000..9638374251
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java
@@ -0,0 +1,141 @@
+/*
+ * 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.sshd;
+
+import static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.flag;
+import static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.positive;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
+import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.HostEntry;
+import org.eclipse.jgit.transport.SshConstants;
+
+/**
+ * A {@link HostConfigEntryResolver} adapted specifically for JGit.
+ * <p>
+ * We use our own config file parser and entry resolution since the default
+ * {@link org.apache.sshd.client.config.hosts.ConfigFileHostEntryResolver
+ * ConfigFileHostEntryResolver} has a number of problems:
+ * </p>
+ * <ul>
+ * <li>It does case-insensitive pattern matching. Matching in OpenSsh is
+ * case-sensitive! Compare also bug 531118.</li>
+ * <li>It only merges values from the global items (before the first "Host"
+ * line) into the host entries. Otherwise it selects the most specific match.
+ * OpenSsh processes <em>all</em> entries in the order they appear in the file
+ * and whenever one matches, it updates values as appropriate.</li>
+ * <li>We have to ensure that ~ replacement uses the same HOME directory as
+ * JGit. Compare bug bug 526175.</li>
+ * </ul>
+ * Therefore, this re-uses the parsing and caching from
+ * {@link OpenSshConfigFile}.
+ *
+ * @since 5.2
+ */
+public class JGitSshConfig implements HostConfigEntryResolver {
+
+ private OpenSshConfigFile configFile;
+
+ /**
+ * Creates a new {@link OpenSshConfigFile} that will read the config from
+ * file {@code config} use the given file {@code home} as "home" directory.
+ *
+ * @param home
+ * user's home directory for the purpose of ~ replacement
+ * @param config
+ * file to load.
+ * @param localUserName
+ * user name of the current user on the local host OS
+ */
+ public JGitSshConfig(@NonNull File home, @NonNull File config,
+ @NonNull String localUserName) {
+ configFile = new OpenSshConfigFile(home, config, localUserName);
+ }
+
+ @Override
+ public HostConfigEntry resolveEffectiveHost(String host, int port,
+ String username) throws IOException {
+ HostEntry entry = configFile.lookup(host, port, username);
+ JGitHostConfigEntry config = new JGitHostConfigEntry();
+ String hostName = entry.getValue(SshConstants.HOST_NAME);
+ if (hostName == null || hostName.isEmpty()) {
+ hostName = host;
+ }
+ config.setHostName(hostName);
+ config.setHost(SshdSocketAddress.isIPv6Address(hostName) ? "" : hostName); //$NON-NLS-1$
+ String user = username != null && !username.isEmpty() ? username
+ : entry.getValue(SshConstants.USER);
+ if (user == null || user.isEmpty()) {
+ user = configFile.getLocalUserName();
+ }
+ config.setUsername(user);
+ int p = port >= 0 ? port : positive(entry.getValue(SshConstants.PORT));
+ config.setPort(p >= 0 ? p : SshConstants.SSH_DEFAULT_PORT);
+ config.setIdentities(entry.getValues(SshConstants.IDENTITY_FILE));
+ config.setIdentitiesOnly(
+ flag(entry.getValue(SshConstants.IDENTITIES_ONLY)));
+ // Apache MINA conflates all keys, even multi-valued ones, in one map
+ // and puts multiple values separated by commas in one string. See
+ // the javadoc on HostConfigEntry.
+ Map<String, String> allOptions = new TreeMap<>(
+ String.CASE_INSENSITIVE_ORDER);
+ allOptions.putAll(entry.getOptions());
+ // And what if a value contains a comma??
+ entry.getMultiValuedOptions().entrySet().stream()
+ .forEach(e -> allOptions.put(e.getKey(),
+ String.join(",", e.getValue()))); //$NON-NLS-1$
+ config.setProperties(allOptions);
+ // The following is an extension from JGitHostConfigEntry
+ config.setMultiValuedOptions(entry.getMultiValuedOptions());
+ return config;
+ }
+
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java
new file mode 100644
index 0000000000..d1865d9f73
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java
@@ -0,0 +1,74 @@
+/*
+ * 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.sshd;
+
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.util.function.Function;
+
+/**
+ * A cache for {@link KeyPair}s.
+ *
+ * @since 5.2
+ */
+public interface KeyCache {
+
+ /**
+ * Obtains a {@link KeyPair} from the cache. Implementations must be
+ * thread-safe.
+ *
+ * @param path
+ * of the key
+ * @param loader
+ * to load the key if it isn't present in the cache yet
+ * @return the {@link KeyPair}, or {@code null} if not present and could not
+ * be loaded
+ */
+ KeyPair get(Path path, Function<? super Path, ? extends KeyPair> loader);
+
+ /**
+ * Removes all {@link KeyPair} from this cache and destroys their private
+ * keys. This cache instance must not be used anymore thereafter.
+ */
+ public void close();
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java
new file mode 100644
index 0000000000..1707c7079d
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java
@@ -0,0 +1,59 @@
+/*
+ * 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.sshd;
+
+/**
+ * A {@code SessionCloseListener} is invoked when a {@link SshdSession} is
+ * closed.
+ */
+@FunctionalInterface
+public interface SessionCloseListener {
+
+ /**
+ * Invoked when a {@link SshdSession} has been closed.
+ *
+ * @param session
+ * that was closed.
+ */
+ void sessionClosed(SshdSession session);
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
new file mode 100644
index 0000000000..7d0e686a28
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
@@ -0,0 +1,485 @@
+/*
+ * 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.sshd;
+
+import static java.text.MessageFormat.format;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.channel.ClientChannelEvent;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CopyMode;
+import org.apache.sshd.client.subsystem.sftp.SftpClientFactory;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.subsystem.sftp.SftpException;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.transport.sshd.SshdText;
+import org.eclipse.jgit.transport.FtpChannel;
+import org.eclipse.jgit.transport.RemoteSession;
+import org.eclipse.jgit.transport.URIish;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An implementation of {@link RemoteSession} based on Apache MINA sshd.
+ *
+ * @since 5.2
+ */
+public class SshdSession implements RemoteSession {
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(SshdSession.class);
+
+ private final CopyOnWriteArrayList<SessionCloseListener> listeners = new CopyOnWriteArrayList<>();
+
+ private final URIish uri;
+
+ private SshClient client;
+
+ private ClientSession session;
+
+ SshdSession(URIish uri, Supplier<SshClient> clientFactory) {
+ this.uri = uri;
+ this.client = clientFactory.get();
+ }
+
+ void connect(Duration timeout) throws IOException {
+ if (!client.isStarted()) {
+ client.start();
+ }
+ try {
+ String username = uri.getUser();
+ String host = uri.getHost();
+ int port = uri.getPort();
+ long t = timeout.toMillis();
+ if (t <= 0) {
+ session = client.connect(username, host, port).verify()
+ .getSession();
+ } else {
+ session = client.connect(username, host, port)
+ .verify(timeout.toMillis()).getSession();
+ }
+ session.addSessionListener(new SessionListener() {
+
+ @Override
+ public void sessionClosed(Session s) {
+ notifyCloseListeners();
+ }
+ });
+ // Authentication timeout is by default 2 minutes.
+ session.auth().verify(session.getAuthTimeout());
+ } catch (IOException e) {
+ disconnect(e);
+ throw e;
+ }
+ }
+
+ /**
+ * Adds a {@link SessionCloseListener} to this session. Has no effect if the
+ * given {@code listener} is already registered with this session.
+ *
+ * @param listener
+ * to add
+ */
+ public void addCloseListener(@NonNull SessionCloseListener listener) {
+ listeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Removes the given {@code listener}; has no effect if the listener is not
+ * currently registered with this session.
+ *
+ * @param listener
+ * to remove
+ */
+ public void removeCloseListener(@NonNull SessionCloseListener listener) {
+ listeners.remove(listener);
+ }
+
+ private void notifyCloseListeners() {
+ for (SessionCloseListener l : listeners) {
+ try {
+ l.sessionClosed(this);
+ } catch (RuntimeException e) {
+ LOG.warn(SshdText.get().closeListenerFailed, e);
+ }
+ }
+ }
+
+ @Override
+ public Process exec(String commandName, int timeout) throws IOException {
+ @SuppressWarnings("resource")
+ ChannelExec exec = session.createExecChannel(commandName);
+ long timeoutMillis = TimeUnit.SECONDS.toMillis(timeout);
+ try {
+ if (timeout <= 0) {
+ exec.open().verify();
+ } else {
+ long start = System.nanoTime();
+ exec.open().verify(timeoutMillis);
+ timeoutMillis -= TimeUnit.NANOSECONDS
+ .toMillis(System.nanoTime() - start);
+ }
+ } catch (IOException e) {
+ exec.close(true);
+ throw e;
+ } catch (RuntimeException e) {
+ exec.close(true);
+ throw e;
+ }
+ if (timeout > 0 && timeoutMillis <= 0) {
+ // We have used up the whole timeout for opening the channel
+ exec.close(true);
+ throw new InterruptedIOException(
+ format(SshdText.get().sshCommandTimeout, commandName,
+ Integer.valueOf(timeout)));
+ }
+ return new SshdExecProcess(exec, commandName, timeoutMillis);
+ }
+
+ /**
+ * Obtain an {@link FtpChannel} to perform SFTP operations in this
+ * {@link SshdSession}.
+ */
+ @Override
+ @NonNull
+ public FtpChannel getFtpChannel() {
+ return new SshdFtpChannel();
+ }
+
+ @Override
+ public void disconnect() {
+ disconnect(null);
+ }
+
+ private void disconnect(Throwable reason) {
+ try {
+ if (session != null) {
+ session.close();
+ session = null;
+ }
+ } catch (IOException e) {
+ if (reason != null) {
+ reason.addSuppressed(e);
+ } else {
+ LOG.error(SshdText.get().sessionCloseFailed, e);
+ }
+ } finally {
+ client.stop();
+ client = null;
+ }
+ }
+
+ private static class SshdExecProcess extends Process {
+
+ private final ChannelExec channel;
+
+ private final long timeoutMillis;
+
+ private final String commandName;
+
+ public SshdExecProcess(ChannelExec channel, String commandName,
+ long timeoutMillis) {
+ this.channel = channel;
+ this.timeoutMillis = timeoutMillis > 0 ? timeoutMillis : -1L;
+ this.commandName = commandName;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return channel.getInvertedIn();
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return channel.getInvertedOut();
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return channel.getInvertedErr();
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ if (waitFor(timeoutMillis, TimeUnit.MILLISECONDS)) {
+ return exitValue();
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long millis = timeout >= 0 ? unit.toMillis(timeout) : -1L;
+ return channel
+ .waitFor(EnumSet.of(ClientChannelEvent.CLOSED), millis)
+ .contains(ClientChannelEvent.CLOSED);
+ }
+
+ @Override
+ public int exitValue() {
+ Integer exitCode = channel.getExitStatus();
+ if (exitCode == null) {
+ throw new IllegalThreadStateException(
+ format(SshdText.get().sshProcessStillRunning,
+ commandName));
+ }
+ return exitCode.intValue();
+ }
+
+ @Override
+ public void destroy() {
+ if (channel.isOpen()) {
+ channel.close(true);
+ }
+ }
+ }
+
+ /**
+ * Helper interface like {@link Supplier}, but possibly raising an
+ * {@link IOException}.
+ *
+ * @param <T>
+ * return type
+ */
+ @FunctionalInterface
+ private interface FtpOperation<T> {
+
+ T call() throws IOException;
+
+ }
+
+ private class SshdFtpChannel implements FtpChannel {
+
+ private SftpClient ftp;
+
+ /** Current working directory. */
+ private String cwd = ""; //$NON-NLS-1$
+
+ @Override
+ public void connect(int timeout, TimeUnit unit) throws IOException {
+ if (timeout <= 0) {
+ session.getProperties().put(
+ SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT,
+ Long.valueOf(Long.MAX_VALUE));
+ } else {
+ session.getProperties().put(
+ SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT,
+ Long.valueOf(unit.toMillis(timeout)));
+ }
+ ftp = SftpClientFactory.instance().createSftpClient(session);
+ try {
+ cd(cwd);
+ } catch (IOException e) {
+ ftp.close();
+ }
+ }
+
+ @Override
+ public void disconnect() {
+ try {
+ ftp.close();
+ } catch (IOException e) {
+ LOG.error(SshdText.get().ftpCloseFailed, e);
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ return session.isAuthenticated() && ftp.isOpen();
+ }
+
+ private String absolute(String path) {
+ if (path.isEmpty()) {
+ return cwd;
+ }
+ // Note: there is no path injection vulnerability here. If
+ // path has too many ".." components, we rely on the server
+ // catching it and returning an error.
+ if (path.charAt(0) != '/') {
+ if (cwd.charAt(cwd.length() - 1) == '/') {
+ return cwd + path;
+ } else {
+ return cwd + '/' + path;
+ }
+ }
+ return path;
+ }
+
+ private <T> T map(FtpOperation<T> op) throws IOException {
+ try {
+ return op.call();
+ } catch (IOException e) {
+ if (e instanceof SftpException) {
+ throw new FtpChannel.FtpException(e.getLocalizedMessage(),
+ ((SftpException) e).getStatus(), e);
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public void cd(String path) throws IOException {
+ cwd = map(() -> ftp.canonicalPath(absolute(path)));
+ if (cwd.isEmpty()) {
+ cwd += '/';
+ }
+ }
+
+ @Override
+ public String pwd() throws IOException {
+ return cwd;
+ }
+
+ @Override
+ public Collection<DirEntry> ls(String path) throws IOException {
+ return map(() -> {
+ List<DirEntry> result = new ArrayList<>();
+ try (CloseableHandle handle = ftp.openDir(absolute(path))) {
+ AtomicReference<Boolean> atEnd = new AtomicReference<>(
+ Boolean.FALSE);
+ while (!atEnd.get().booleanValue()) {
+ List<SftpClient.DirEntry> chunk = ftp.readDir(handle,
+ atEnd);
+ if (chunk == null) {
+ break;
+ }
+ for (SftpClient.DirEntry remote : chunk) {
+ result.add(new DirEntry() {
+
+ @Override
+ public String getFilename() {
+ return remote.getFilename();
+ }
+
+ @Override
+ public long getModifiedTime() {
+ return remote.getAttributes()
+ .getModifyTime().toMillis();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return remote.getAttributes().isDirectory();
+ }
+
+ });
+ }
+ }
+ }
+ return result;
+ });
+ }
+
+ @Override
+ public void rmdir(String path) throws IOException {
+ map(() -> {
+ ftp.rmdir(absolute(path));
+ return null;
+ });
+
+ }
+
+ @Override
+ public void mkdir(String path) throws IOException {
+ map(() -> {
+ ftp.mkdir(absolute(path));
+ return null;
+ });
+ }
+
+ @Override
+ public InputStream get(String path) throws IOException {
+ return map(() -> ftp.read(absolute(path)));
+ }
+
+ @Override
+ public OutputStream put(String path) throws IOException {
+ return map(() -> ftp.write(absolute(path)));
+ }
+
+ @Override
+ public void rm(String path) throws IOException {
+ map(() -> {
+ ftp.remove(absolute(path));
+ return null;
+ });
+ }
+
+ @Override
+ public void rename(String from, String to) throws IOException {
+ map(() -> {
+ String src = absolute(from);
+ String dest = absolute(to);
+ try {
+ ftp.rename(src, dest, CopyMode.Atomic, CopyMode.Overwrite);
+ } catch (UnsupportedOperationException e) {
+ // Older server cannot do POSIX rename...
+ if (!src.equals(dest)) {
+ delete(dest);
+ ftp.rename(src, dest);
+ }
+ }
+ return null;
+ });
+ }
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
new file mode 100644
index 0000000000..862b5590e9
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
@@ -0,0 +1,436 @@
+/*
+ * 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.sshd;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import org.apache.sshd.client.ClientBuilder;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.auth.UserAuth;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
+import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.compression.BuiltinCompressions;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
+import org.eclipse.jgit.internal.transport.sshd.JGitPublicKeyAuthFactory;
+import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
+import org.eclipse.jgit.internal.transport.sshd.JGitUserInteraction;
+import org.eclipse.jgit.internal.transport.sshd.OpenSshServerKeyVerifier;
+import org.eclipse.jgit.internal.transport.sshd.SshdText;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshConstants;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * A {@link SshSessionFactory} that uses Apache MINA sshd.
+ *
+ * @since 5.2
+ */
+public class SshdSessionFactory extends SshSessionFactory implements Closeable {
+
+ private final AtomicBoolean closing = new AtomicBoolean();
+
+ private final Set<SshdSession> sessions = new HashSet<>();
+
+ private final Map<Tuple, HostConfigEntryResolver> defaultHostConfigEntryResolver = new ConcurrentHashMap<>();
+
+ private final Map<Tuple, ServerKeyVerifier> defaultServerKeyVerifier = new ConcurrentHashMap<>();
+
+ private final Map<Tuple, FileKeyPairProvider> defaultKeys = new ConcurrentHashMap<>();
+
+ private final KeyCache keyCache;
+
+ private File sshDirectory;
+
+ private File homeDirectory;
+
+ /**
+ * Creates a new {@link SshdSessionFactory} without {@link KeyCache}.
+ */
+ public SshdSessionFactory() {
+ this(null);
+ }
+
+ /**
+ * Creates a new {@link SshdSessionFactory} using the given
+ * {@link KeyCache}. The {@code keyCache} is used for all sessions created
+ * through this session factory; cached keys are destroyed when the session
+ * factory is {@link #close() closed}.
+ * <p>
+ * Caching ssh keys in memory for an extended period of time is generally
+ * considered bad practice, but there may be circumstances where using a
+ * {@link KeyCache} is still the right choice, for instance to avoid that a
+ * user gets prompted several times for the same password for the same key.
+ * In general, however, it is preferable <em>not</em> to use a key cache but
+ * to use a {@link #createFilePasswordProvider(CredentialsProvider)
+ * FilePasswordProvider} that has access to some secure storage and can save
+ * and retrieve passwords from there without user interaction. Another
+ * approach is to use an ssh agent.
+ * </p>
+ * <p>
+ * Note that the underlying ssh library (Apache MINA sshd) may or may not
+ * keep ssh keys in memory for unspecified periods of time irrespective of
+ * the use of a {@link KeyCache}.
+ * </p>
+ *
+ * @param keyCache
+ * {@link KeyCache} to use for caching ssh keys, or {@code null}
+ * to not use a key cache
+ */
+ public SshdSessionFactory(KeyCache keyCache) {
+ super();
+ this.keyCache = keyCache;
+ }
+
+ /** A simple general map key. */
+ private static final class Tuple {
+ private Object[] objects;
+
+ public Tuple(Object... objects) {
+ this.objects = objects;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj != null && obj.getClass() == Tuple.class) {
+ Tuple other = (Tuple) obj;
+ return Arrays.equals(objects, other.objects);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(objects);
+ }
+ }
+
+ // We can't really use a single client. Clients need to be stopped
+ // properly, and we don't really know when to do that. Instead we use
+ // a dedicated SshClient instance per session. We need a bit of caching to
+ // avoid re-loading the ssh config and keys repeatedly.
+
+ @Override
+ public SshdSession getSession(URIish uri,
+ CredentialsProvider credentialsProvider, FS fs, int tms)
+ throws TransportException {
+ SshdSession session = null;
+ try {
+ session = new SshdSession(uri, () -> {
+ File home = getHomeDirectory();
+ if (home == null) {
+ // Always use the detected filesystem for the user home!
+ // It makes no sense to have different "user home"
+ // directories depending on what file system a repository
+ // is.
+ home = FS.DETECTED.userHome();
+ }
+ File sshDir = getSshDirectory();
+ if (sshDir == null) {
+ sshDir = new File(home, SshConstants.SSH_DIR);
+ }
+ HostConfigEntryResolver configFile = getHostConfigEntryResolver(
+ home, sshDir);
+ KeyPairProvider defaultKeysProvider = getDefaultKeysProvider(
+ sshDir);
+ SshClient client = ClientBuilder.builder()
+ .factory(JGitSshClient::new)
+ .filePasswordProvider(
+ createFilePasswordProvider(credentialsProvider))
+ .hostConfigEntryResolver(configFile)
+ .serverKeyVerifier(getServerKeyVerifier(home, sshDir))
+ .compressionFactories(
+ new ArrayList<>(BuiltinCompressions.VALUES))
+ .build();
+ client.setUserInteraction(
+ new JGitUserInteraction(credentialsProvider));
+ client.setUserAuthFactories(getUserAuthFactories());
+ client.setKeyPairProvider(defaultKeysProvider);
+ // JGit-specific things:
+ JGitSshClient jgitClient = (JGitSshClient) client;
+ jgitClient.setKeyCache(getKeyCache());
+ jgitClient.setCredentialsProvider(credentialsProvider);
+ // Other things?
+ return client;
+ });
+ session.addCloseListener(s -> unregister(s));
+ register(session);
+ session.connect(Duration.ofMillis(tms));
+ return session;
+ } catch (Exception e) {
+ unregister(session);
+ throw new TransportException(uri, e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void close() {
+ closing.set(true);
+ boolean cleanKeys = false;
+ synchronized (this) {
+ cleanKeys = sessions.isEmpty();
+ }
+ if (cleanKeys) {
+ KeyCache cache = getKeyCache();
+ if (cache != null) {
+ cache.close();
+ }
+ }
+ }
+
+ private void register(SshdSession newSession) throws IOException {
+ if (newSession == null) {
+ return;
+ }
+ if (closing.get()) {
+ throw new IOException(SshdText.get().sshClosingDown);
+ }
+ synchronized (this) {
+ sessions.add(newSession);
+ }
+ }
+
+ private void unregister(SshdSession oldSession) {
+ boolean cleanKeys = false;
+ synchronized (this) {
+ sessions.remove(oldSession);
+ cleanKeys = closing.get() && sessions.isEmpty();
+ }
+ if (cleanKeys) {
+ KeyCache cache = getKeyCache();
+ if (cache != null) {
+ cache.close();
+ }
+ }
+ }
+
+ /**
+ * Set a global directory to use as the user's home directory
+ *
+ * @param homeDir
+ * to use
+ */
+ public void setHomeDirectory(@NonNull File homeDir) {
+ if (homeDir.isAbsolute()) {
+ homeDirectory = homeDir;
+ } else {
+ homeDirectory = homeDir.getAbsoluteFile();
+ }
+ }
+
+ /**
+ * Retrieves the global user home directory
+ *
+ * @return the directory, or {@code null} if not set
+ */
+ public File getHomeDirectory() {
+ return homeDirectory;
+ }
+
+ /**
+ * Set a global directory to use as the .ssh directory
+ *
+ * @param sshDir
+ * to use
+ */
+ public void setSshDirectory(@NonNull File sshDir) {
+ if (sshDir.isAbsolute()) {
+ sshDirectory = sshDir;
+ } else {
+ sshDirectory = sshDir.getAbsoluteFile();
+ }
+ }
+
+ /**
+ * Retrieves the global .ssh directory
+ *
+ * @return the directory, or {@code null} if not set
+ */
+ public File getSshDirectory() {
+ return sshDirectory;
+ }
+
+ /**
+ * Obtain a {@link HostConfigEntryResolver} to read the ssh config file and
+ * to determine host entries for connections.
+ *
+ * @param homeDir
+ * home directory to use for ~ replacement
+ * @param sshDir
+ * to use for looking for the config file
+ * @return the resolver
+ */
+ @NonNull
+ protected HostConfigEntryResolver getHostConfigEntryResolver(
+ @NonNull File homeDir, @NonNull File sshDir) {
+ return defaultHostConfigEntryResolver.computeIfAbsent(
+ new Tuple(homeDir, sshDir),
+ t -> new JGitSshConfig(homeDir,
+ new File(sshDir, SshConstants.CONFIG),
+ getLocalUserName()));
+ }
+
+ /**
+ * Obtain a {@link ServerKeyVerifier} to read known_hosts files and to
+ * verify server host keys. The default implementation returns a
+ * {@link ServerKeyVerifier} that recognizes the two openssh standard files
+ * {@code ~/.ssh/known_hosts} and {@code ~/.ssh/known_hosts2} as well as any
+ * files configured via the {@code UserKnownHostsFile} option in the ssh
+ * config file.
+ *
+ * @param homeDir
+ * home directory to use for ~ replacement
+ * @param sshDir
+ * representing ~/.ssh/
+ * @return the resolver
+ */
+ @NonNull
+ protected ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir,
+ @NonNull File sshDir) {
+ return defaultServerKeyVerifier.computeIfAbsent(
+ new Tuple(homeDir, sshDir),
+ t -> new OpenSshServerKeyVerifier(true,
+ Arrays.asList(
+ new File(sshDir, SshConstants.KNOWN_HOSTS),
+ new File(sshDir,
+ SshConstants.KNOWN_HOSTS + '2'))));
+ }
+
+ /**
+ * Determines a {@link KeyPairProvider} to use to load the default keys.
+ *
+ * @param sshDir
+ * to look in for keys
+ * @return the {@link KeyPairProvider}
+ */
+ @NonNull
+ protected KeyPairProvider getDefaultKeysProvider(@NonNull File sshDir) {
+ return defaultKeys.computeIfAbsent(new Tuple(sshDir),
+ t -> new CachingKeyPairProvider(getDefaultIdentities(sshDir),
+ getKeyCache()));
+ }
+
+ /**
+ * Gets a list of default identities, i.e., private key files that shall
+ * always be tried for public key authentication. Typically those are
+ * ~/.ssh/id_dsa, ~/.ssh/id_rsa, and so on. The default implementation
+ * returns the files defined in {@link SshConstants#DEFAULT_IDENTITIES}.
+ *
+ * @param sshDir
+ * the directory that represents ~/.ssh/
+ * @return a possibly empty list of paths containing default identities
+ * (private keys)
+ */
+ @NonNull
+ protected List<Path> getDefaultIdentities(@NonNull File sshDir) {
+ return Arrays
+ .asList(SshConstants.DEFAULT_IDENTITIES).stream()
+ .map(s -> new File(sshDir, s).toPath()).filter(Files::exists)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Obtains the {@link KeyCache} to use to cache loaded keys.
+ *
+ * @return the {@link KeyCache}, or {@code null} if none.
+ */
+ protected final KeyCache getKeyCache() {
+ return keyCache;
+ }
+
+ /**
+ * Creates a {@link FilePasswordProvider} for a new session.
+ *
+ * @param provider
+ * the {@link CredentialsProvider} to delegate for for user
+ * interactions
+ * @return a new {@link FilePasswordProvider}
+ */
+ @NonNull
+ protected FilePasswordProvider createFilePasswordProvider(
+ CredentialsProvider provider) {
+ return new IdentityPasswordProvider(provider);
+ }
+
+ /**
+ * Gets the user authentication mechanisms (or rather, factories for them).
+ * By default this returns public-key, keyboard-interactive, and password,
+ * in that order. (I.e., we don't do gssapi-with-mic or hostbased (yet)).
+ *
+ * @return the non-empty list of factories.
+ */
+ @NonNull
+ protected List<NamedFactory<UserAuth>> getUserAuthFactories() {
+ return Collections.unmodifiableList(
+ Arrays.asList(JGitPublicKeyAuthFactory.INSTANCE,
+ UserAuthKeyboardInteractiveFactory.INSTANCE,
+ UserAuthPasswordFactory.INSTANCE));
+ }
+}
diff --git a/org.eclipse.jgit.test/.classpath b/org.eclipse.jgit.test/.classpath
index 3a0a10e33c..7cc18cca34 100644
--- a/org.eclipse.jgit.test/.classpath
+++ b/org.eclipse.jgit.test/.classpath
@@ -16,6 +16,7 @@
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
+ <classpathentry kind="src" path="resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD
index 2082e7eac0..7165651496 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -6,7 +6,10 @@ load(
PKG = "tst/org/eclipse/jgit/"
-HELPERS = glob(["src/**/*.java"]) + [PKG + c for c in [
+HELPERS = glob(
+ ["src/**/*.java"],
+ exclude = ["src/org/eclipse/jgit/transport/ssh/*.java"]
+ ) + [PKG + c for c in [
"api/AbstractRemoteCommandTest.java",
"diff/AbstractDiffTestCase.java",
"internal/storage/file/GcTestCase.java",
@@ -20,8 +23,6 @@ HELPERS = glob(["src/**/*.java"]) + [PKG + c for c in [
"revwalk/RevWalkTestCase.java",
"transport/ObjectIdMatcher.java",
"transport/SpiTransport.java",
- "transport/ssh/SshTestBase.java",
- "transport/ssh/SshTestHarness.java",
"treewalk/FileTreeIteratorWithTimeControl.java",
"treewalk/filter/AlwaysCloneTreeFilter.java",
"test/resources/SampleDataRepositoryTestCase.java",
@@ -34,6 +35,8 @@ DATA = [
PKG + "lib/sorttest.gitindex.dat",
]
+RESOURCES = glob(["resources/**"])
+
tests(glob(
["tst/**/*.java"],
exclude = HELPERS + DATA,
@@ -54,6 +57,25 @@ java_library(
],
)
+java_library(
+ name = "sshd-helpers",
+ testonly = 1,
+ srcs = glob(["src/org/eclipse/jgit/transport/ssh/*.java"]),
+ resource_strip_prefix = "org.eclipse.jgit.test/resources",
+ resources = RESOURCES,
+ deps = [
+ "//lib:junit",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit:junit",
+ "//lib:jsch",
+ "//lib:sshd-core",
+ "//lib:sshd-sftp",
+ ],
+ visibility = [
+ "//org.eclipse.jgit.ssh.apache.test:__pkg__",
+ ],
+)
+
java_import(
name = "tst_rsrc",
jars = [":tst_rsrc_jar"],
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 6514277ac5..94681178e7 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -66,3 +66,4 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.slf4j;version="[1.7.0,2.0.0)"
Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
+Export-Package: org.eclipse.jgit.transport.ssh;version="5.2.0";x-friends:="org.eclipse.jgit.ssh.apache.test"
diff --git a/org.eclipse.jgit.test/build.properties b/org.eclipse.jgit.test/build.properties
index 7dc26c0b0d..78c8f55f3a 100644
--- a/org.eclipse.jgit.test/build.properties
+++ b/org.eclipse.jgit.test/build.properties
@@ -1,7 +1,8 @@
source.. = tst/,\
tst-rsrc/,\
exttst/,\
- src/
+ src/,\
+ resources/
bin.includes = META-INF/,\
.,\
plugin.properties,\
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 3d5df9a68a..4099c89c09 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -154,6 +154,18 @@
</testResource>
</testResources>
+ <resources>
+ <resource>
+ <directory>.</directory>
+ <includes>
+ <include>plugin.properties</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>resources/</directory>
+ </resource>
+ </resources>
+
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa
index f097516df2..f097516df2 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa.pub
index 676685332e..676685332e 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass
index 375d38fe43..375d38fe43 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub
index 676685332e..676685332e 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256
index 8a4c864afa..8a4c864afa 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub
index 43540ec0ec..43540ec0ec 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass
index b767c8e99a..b767c8e99a 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub
index 43540ec0ec..43540ec0ec 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384
index dc2ac86508..dc2ac86508 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub
index 3e813a5e48..3e813a5e48 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass
index 06032d049f..06032d049f 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub
index 3e813a5e48..3e813a5e48 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521
index c28151e5ab..c28151e5ab 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub
index 9bac1e80f0..9bac1e80f0 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass
index c1c1bbaced..c1c1bbaced 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub
index 9bac1e80f0..9bac1e80f0 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519
index 02afa54788..02afa54788 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519.pub
index 7857db5602..7857db5602 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass
index 7ad4a77056..7ad4a77056 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub
index 7857db5602..7857db5602 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024
index 0b403674fa..0b403674fa 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub
index 4aded97ab6..4aded97ab6 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass
index 0b66dc0aa9..0b66dc0aa9 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub
index 4aded97ab6..4aded97ab6 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048
index a2d7d62310..a2d7d62310 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub
index b787e36483..b787e36483 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass
index 7b3a3f4e58..7b3a3f4e58 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub
index b787e36483..b787e36483 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072
index 10d622c905..10d622c905 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub
index 686d3b06b1..686d3b06b1 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass
index 353a24c206..353a24c206 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub
index 686d3b06b1..686d3b06b1 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096 b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096
index 1a10b388e6..1a10b388e6 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub
index 3c3c16feeb..3c3c16feeb 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass
index 96e29fc15c..96e29fc15c 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub
index 3c3c16feeb..3c3c16feeb 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub
+++ b/org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
index 4afe6e2422..2f623e3305 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
@@ -174,8 +174,14 @@ public abstract class SshTestBase extends SshTestHarness {
@Test
public void testSshWithConfigEncryptedUnusedKeyInConfigFirst()
throws Exception {
- // Test cannot pass with JSch; it handles only one IdentityFile
- assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory));
+ // Test cannot pass with JSch; it handles only one IdentityFile.
+ // assumeTrue(!(getSessionFactory() instanceof
+ // JschConfigSessionFactory)); gives in bazel a failure with "Never
+ // found parameters that satisfied method assumptions."
+ // In maven it's fine!?
+ if (getSessionFactory() instanceof JschConfigSessionFactory) {
+ return;
+ }
// Copy the encrypted test key from the bundle.
File encryptedKey = new File(sshDir, "id_dsa_test_key");
copyTestResource("id_dsa_testpass", encryptedKey);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
index 347c72b3d7..347c72b3d7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl
index b9ad8b2126..48c3bc36c8 100644
--- a/org.eclipse.jgit.test/tests.bzl
+++ b/org.eclipse.jgit.test/tests.bzl
@@ -47,6 +47,7 @@ def tests(tests):
"//lib:jzlib",
"//lib:sshd-core",
"//lib:sshd-sftp",
+ ":sshd-helpers",
]
heap_size = "-Xmx256m"
if src.endswith("HugeCommitMessageTest.java"):
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index aec1dd890e..6fbb0e548e 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -75,15 +75,19 @@ Export-Package: org.eclipse.jgit.annotations;version="5.2.0",
org.eclipse.jgit.http.server,
org.eclipse.jgit.lfs,
org.eclipse.jgit.pgm,
- org.eclipse.jgit.pgm.test",
+ org.eclipse.jgit.pgm.test,
+ org.eclipse.jgit.ssh.apache",
org.eclipse.jgit.internal.storage.io;version="5.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.storage.pack;version="5.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.storage.reftable;version="5.2.0";
- x-friends:="org.eclipse.jgit.http.test,org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ x-friends:="org.eclipse.jgit.http.test,
+ org.eclipse.jgit.junit,
+ org.eclipse.jgit.test,
+ org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.storage.reftree;version="5.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.submodule;version="5.2.0";x-internal:=true,
org.eclipse.jgit.internal.transport.parser;version="5.2.0";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.ssh;version="5.2.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.ssh;version="5.2.0";x-friends:="org.eclipse.jgit.ssh.apache",
org.eclipse.jgit.lib;version="5.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
diff --git a/pom.xml b/pom.xml
index 610a9a3ef8..c3e6be6c37 100644
--- a/pom.xml
+++ b/pom.xml
@@ -934,6 +934,7 @@
<module>org.eclipse.jgit.ui</module>
<module>org.eclipse.jgit.http.apache</module>
<module>org.eclipse.jgit.http.server</module>
+ <module>org.eclipse.jgit.ssh.apache</module>
<module>org.eclipse.jgit.pgm</module>
<module>org.eclipse.jgit.lfs</module>
<module>org.eclipse.jgit.lfs.server</module>
@@ -946,6 +947,7 @@
<module>org.eclipse.jgit.pgm.test</module>
<module>org.eclipse.jgit.lfs.test</module>
<module>org.eclipse.jgit.lfs.server.test</module>
+ <module>org.eclipse.jgit.ssh.apache.test</module>
</modules>
</project>