Browse Source

Apache MINA sshd client

Add a new ssh client implementation based on Apach MINA sshd 2.0.0.

This implementation uses JGit's own config file parser and host entry
resolver. Code inspection of the Apache MINA implementation revealed
a few bugs or idiosyncrasies that immediately would re-introduce bugs
already fixed in the past in JGit.

Apache MINA sshd is not without quirks either, and I had to configure
and override more than I had expected. But at least it was all doable
in clean ways.

Apache MINA boasts support for Bouncy Castle, so in theory this should
open the way to using more ssh key algorithms, such as ed25519.

The implementation is in a separate bundle and is still not used in
the core org.eclipse.jgit bundle. The tests re-use the ssh tests from
the core test bundle.

Bug: 520927
Change-Id: Ib35e73c35799140fe050d1ff4fb18d0d3596580e
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
tags/v5.2.0.201811281532-m3
Thomas Wolf 5 years ago
parent
commit
488d95571f
100 changed files with 5731 additions and 6 deletions
  1. 4
    0
      lib/BUILD
  2. 11
    0
      org.eclipse.jgit.ssh.apache.test/.classpath
  3. 2
    0
      org.eclipse.jgit.ssh.apache.test/.gitignore
  4. 28
    0
      org.eclipse.jgit.ssh.apache.test/.project
  5. 3
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs
  6. 3
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs
  7. 399
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs
  8. 66
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs
  9. 4
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs
  10. 3
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs
  11. 104
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs
  12. 3
    0
      org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs
  13. 18
    0
      org.eclipse.jgit.ssh.apache.test/BUILD
  14. 17
    0
      org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
  15. 96
    0
      org.eclipse.jgit.ssh.apache.test/about.html
  16. 5
    0
      org.eclipse.jgit.ssh.apache.test/build.properties
  17. 2
    0
      org.eclipse.jgit.ssh.apache.test/plugin.properties
  18. 145
    0
      org.eclipse.jgit.ssh.apache.test/pom.xml
  19. 83
    0
      org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
  20. 8
    0
      org.eclipse.jgit.ssh.apache/.classpath
  21. 125
    0
      org.eclipse.jgit.ssh.apache/.fbprefs
  22. 2
    0
      org.eclipse.jgit.ssh.apache/.gitignore
  23. 34
    0
      org.eclipse.jgit.ssh.apache/.project
  24. 3
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs
  25. 3
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs
  26. 399
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs
  27. 66
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs
  28. 4
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs
  29. 3
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs
  30. 104
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs
  31. 3
    0
      org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs
  32. 18
    0
      org.eclipse.jgit.ssh.apache/BUILD
  33. 76
    0
      org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
  34. 96
    0
      org.eclipse.jgit.ssh.apache/about.html
  35. 7
    0
      org.eclipse.jgit.ssh.apache/build.properties
  36. 2
    0
      org.eclipse.jgit.ssh.apache/plugin.properties
  37. 206
    0
      org.eclipse.jgit.ssh.apache/pom.xml
  38. 36
    0
      org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
  39. 168
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
  40. 114
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
  41. 83
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java
  42. 103
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
  43. 275
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
  44. 320
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
  45. 169
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
  46. 718
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
  47. 50
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
  48. 120
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
  49. 87
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java
  50. 88
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java
  51. 141
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java
  52. 74
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java
  53. 59
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java
  54. 485
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
  55. 436
    0
      org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
  56. 1
    0
      org.eclipse.jgit.test/.classpath
  57. 25
    3
      org.eclipse.jgit.test/BUILD
  58. 1
    0
      org.eclipse.jgit.test/META-INF/MANIFEST.MF
  59. 2
    1
      org.eclipse.jgit.test/build.properties
  60. 12
    0
      org.eclipse.jgit.test/pom.xml
  61. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa
  62. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa.pub
  63. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass
  64. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub
  65. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256
  66. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub
  67. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass
  68. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub
  69. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384
  70. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub
  71. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass
  72. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub
  73. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521
  74. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub
  75. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass
  76. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub
  77. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519
  78. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519.pub
  79. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass
  80. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub
  81. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024
  82. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub
  83. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass
  84. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub
  85. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048
  86. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub
  87. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass
  88. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub
  89. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072
  90. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub
  91. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass
  92. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub
  93. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096
  94. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub
  95. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass
  96. 0
    0
      org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub
  97. 8
    2
      org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
  98. 0
    0
      org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
  99. 1
    0
      org.eclipse.jgit.test/tests.bzl
  100. 0
    0
      org.eclipse.jgit/META-INF/MANIFEST.MF

+ 4
- 0
lib/BUILD View File

@@ -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"],
)

+ 11
- 0
org.eclipse.jgit.ssh.apache.test/.classpath View File

@@ -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>

+ 2
- 0
org.eclipse.jgit.ssh.apache.test/.gitignore View File

@@ -0,0 +1,2 @@
/bin
/target

+ 28
- 0
org.eclipse.jgit.ssh.apache.test/.project View File

@@ -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>

+ 3
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.resources.prefs View File

@@ -0,0 +1,3 @@
#Sat Dec 20 21:21:24 CET 2008
eclipse.preferences.version=1
encoding/<project>=UTF-8

+ 3
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.core.runtime.prefs View File

@@ -0,0 +1,3 @@
#Mon Mar 24 18:55:56 EDT 2008
eclipse.preferences.version=1
line.separator=\n

+ 399
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs View File

@@ -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

+ 66
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.ui.prefs View File

@@ -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

+ 4
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.tasks.ui.prefs View File

@@ -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

+ 3
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.mylyn.team.ui.prefs View File

@@ -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

+ 104
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.api.tools.prefs View File

@@ -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

+ 3
- 0
org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.pde.core.prefs View File

@@ -0,0 +1,3 @@
#Thu Jan 14 14:34:32 CST 2010
eclipse.preferences.version=1
resolve.requirebundle=false

+ 18
- 0
org.eclipse.jgit.ssh.apache.test/BUILD View File

@@ -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",
],
)

+ 17
- 0
org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF View File

@@ -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)"

+ 96
- 0
org.eclipse.jgit.ssh.apache.test/about.html View File

@@ -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>

+ 5
- 0
org.eclipse.jgit.ssh.apache.test/build.properties View File

@@ -0,0 +1,5 @@
source.. = tst/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.properties

+ 2
- 0
org.eclipse.jgit.ssh.apache.test/plugin.properties View File

@@ -0,0 +1,2 @@
plugin_name=JGit Tests for SSH with Apache MINA sshd
provider_name=Eclipse JGit

+ 145
- 0
org.eclipse.jgit.ssh.apache.test/pom.xml View File

@@ -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>

+ 83
- 0
org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java View File

@@ -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);
}
}
}

}

+ 8
- 0
org.eclipse.jgit.ssh.apache/.classpath View File

@@ -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>

+ 125
- 0
org.eclipse.jgit.ssh.apache/.fbprefs View File

@@ -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

+ 2
- 0
org.eclipse.jgit.ssh.apache/.gitignore View File

@@ -0,0 +1,2 @@
/bin
/target

+ 34
- 0
org.eclipse.jgit.ssh.apache/.project View File

@@ -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>

+ 3
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.resources.prefs View File

@@ -0,0 +1,3 @@
#Mon Aug 11 16:46:12 PDT 2008
eclipse.preferences.version=1
encoding/<project>=UTF-8

+ 3
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.core.runtime.prefs View File

@@ -0,0 +1,3 @@
#Mon Mar 24 18:55:50 EDT 2008
eclipse.preferences.version=1
line.separator=\n

+ 399
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs View File

@@ -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

+ 66
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.ui.prefs View File

@@ -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

+ 4
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.tasks.ui.prefs View File

@@ -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

+ 3
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.mylyn.team.ui.prefs View File

@@ -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

+ 104
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.api.tools.prefs View File

@@ -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

+ 3
- 0
org.eclipse.jgit.ssh.apache/.settings/org.eclipse.pde.core.prefs View File

@@ -0,0 +1,3 @@
#Thu Jan 14 14:34:32 CST 2010
eclipse.preferences.version=1
resolve.requirebundle=false

+ 18
- 0
org.eclipse.jgit.ssh.apache/BUILD View File

@@ -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",
],
)

+ 76
- 0
org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF View File

@@ -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)"

+ 96
- 0
org.eclipse.jgit.ssh.apache/about.html View File

@@ -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>

+ 7
- 0
org.eclipse.jgit.ssh.apache/build.properties View File

@@ -0,0 +1,7 @@
source.. = src/,\
resources/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.properties,\
about.html

+ 2
- 0
org.eclipse.jgit.ssh.apache/plugin.properties View File

@@ -0,0 +1,2 @@
plugin_name=JGit SSH support based on Apache MINA sshd
provider_name=Eclipse JGit

+ 206
- 0
org.eclipse.jgit.ssh.apache/pom.xml View File

@@ -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>

+ 36
- 0
org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties View File

@@ -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

+ 168
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java View File

@@ -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;
}

}
}

+ 114
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java View File

@@ -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;
}

}

+ 83
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java View File

@@ -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();
}
}

+ 103
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java View File

@@ -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;
}
}

+ 275
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java View File

@@ -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);
}
}
}

+ 320
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java View File

@@ -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;
}

};
}

}
}

+ 169
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java View File

@@ -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);
}
}

+ 718
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java View File

@@ -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);
}
}

}

+ 50
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java View File

@@ -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;

}

+ 120
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java View File

@@ -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();
}
}

}

+ 87
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitHostConfigEntry.java View File

@@ -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);
}

}

+ 88
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitKeyCache.java View File

@@ -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();
}
}

+ 141
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/JGitSshConfig.java View File

@@ -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;
}

}

+ 74
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyCache.java View File

@@ -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();
}

+ 59
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SessionCloseListener.java View File

@@ -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);
}

+ 485
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java View File

@@ -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;
});
}
}
}

+ 436
- 0
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java View File

@@ -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));
}
}

+ 1
- 0
org.eclipse.jgit.test/.classpath View File

@@ -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"/>

+ 25
- 3
org.eclipse.jgit.test/BUILD View File

@@ -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"],

+ 1
- 0
org.eclipse.jgit.test/META-INF/MANIFEST.MF View File

@@ -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"

+ 2
- 1
org.eclipse.jgit.test/build.properties View File

@@ -1,7 +1,8 @@
source.. = tst/,\
tst-rsrc/,\
exttst/,\
src/
src/,\
resources/
bin.includes = META-INF/,\
.,\
plugin.properties,\

+ 12
- 0
org.eclipse.jgit.test/pom.xml View File

@@ -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>

org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_dsa_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_256_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_384_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ecdsa_521_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_ed25519_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_1024_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_2048_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_3072_testpass.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096 → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096 View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096.pub View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass View File


org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub → org.eclipse.jgit.test/resources/org/eclipse/jgit/transport/ssh/id_rsa_4096_testpass.pub View File


org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestBase.java → org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java View File

@@ -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);

org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ssh/SshTestHarness.java → org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java View File


+ 1
- 0
org.eclipse.jgit.test/tests.bzl View File

@@ -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"):

+ 0
- 0
org.eclipse.jgit/META-INF/MANIFEST.MF View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save