Blob Blame History Raw
From b01b878f39354d6cc8022ee9fea937049ecd4777 Mon Sep 17 00:00:00 2001
From: Mat Booth <mat.booth@redhat.com>
Date: Fri, 7 Dec 2018 10:33:23 +0000
Subject: [PATCH] Port to apache-sshd 2.2.0

IoConnector.connect() grew extra parameters to support specifying
the local bind port/address and optional context. Passing nulls
continues to use an automatically selected ephemeral port/address,
with no context.

The shutdownOnExit parameter was removed everywhere the use of
'java.util.concurrent.ExecutorService' was substituted for the use
of 'org.apache.sshd.common.util.threads.ExecutorService'
---
 .../META-INF/MANIFEST.MF                      |  42 +++----
 org.eclipse.jgit.junit.ssh/pom.xml            |   2 +-
 .../jgit/junit/ssh/SshTestGitServer.java      |  30 +++--
 .../META-INF/MANIFEST.MF                      |  80 ++++++------
 org.eclipse.jgit.ssh.apache/pom.xml           |   2 +-
 .../sshd/CachingKeyPairProvider.java          |  96 +++------------
 .../sshd/EncryptedFileKeyPairProvider.java    |  45 +++----
 .../transport/sshd/JGitClientSession.java     |  12 +-
 .../transport/sshd/JGitPublicKeyIterator.java |  15 ++-
 .../transport/sshd/JGitSshClient.java         |  56 ++++-----
 .../transport/sshd/JGitSshConfig.java         |   5 +-
 .../sshd/OpenSshServerKeyVerifier.java        |   2 +-
 .../sshd/PasswordProviderWrapper.java         |  42 +++----
 .../sshd/RepeatingFilePasswordProvider.java   | 115 ------------------
 .../transport/sshd/SshdSessionFactory.java    |  21 ++--
 pom.xml                                       |   2 +-
 16 files changed, 202 insertions(+), 365 deletions(-)
 delete mode 100644 org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java

diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index cf6cf1a15..85cf64f05 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -8,27 +8,27 @@ Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.sshd.common;version="[2.0.0,2.1.0)",
- org.apache.sshd.common.config.keys;version="[2.0.0,2.1.0)",
- org.apache.sshd.common.file.virtualfs;version="[2.0.0,2.1.0)",
- org.apache.sshd.common.helpers;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.session;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.logging;version="[2.0.0,2.1.0)",
- org.apache.sshd.common.util.security;version="[2.0.0,2.1.0)",
- org.apache.sshd.server;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.auth;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.auth.gss;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.auth.keyboard;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.auth.password;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.command;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.session;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.shell;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.subsystem;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.subsystem.sftp;version="[2.0.0,2.1.0)",
+Import-Package: org.apache.sshd.common;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.config.keys;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.file.virtualfs;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.helpers;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.io;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.kex;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.keyprovider;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.session;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.buffer;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.logging;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.security;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.auth;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.auth.gss;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.auth.keyboard;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.auth.password;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.command;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.session;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.shell;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.subsystem;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.subsystem.sftp;version="[2.2.0,2.3.0)",
  org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
  org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
  org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index 22e3bb538..87e731463 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -73,7 +73,7 @@
 
     <dependency>
       <groupId>org.apache.sshd</groupId>
-      <artifactId>sshd-core</artifactId>
+      <artifactId>sshd-osgi</artifactId>
       <version>${apache-sshd-version}</version>
     </dependency>
 
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
index f5af2e5ce..03ca0b453 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
@@ -55,10 +55,9 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.KeyUtils;
@@ -67,6 +66,8 @@
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.common.util.threads.CloseableExecutorService;
+import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.ServerAuthenticationManager;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.UserAuth;
@@ -110,8 +111,8 @@
 	@NonNull
 	protected PublicKey testKey;
 
-	private final ExecutorService executorService = Executors
-			.newFixedThreadPool(2);
+	private final CloseableExecutorService executorService = ThreadUtils
+			.newFixedThreadPool("", 2);
 
 	/**
 	 * Creates a ssh git <em>test</em> server. It serves one single repository,
@@ -138,11 +139,12 @@ public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
 		server = SshServer.setUpDefaultServer();
 		// Set host key
 		try (ByteArrayInputStream in = new ByteArrayInputStream(hostKey)) {
-			hostKeys.add(SecurityUtils.loadKeyPairIdentity("", in, null));
+			SecurityUtils.loadKeyPairIdentities(null, NamedResource.ofName(""),
+					in, null).forEach(hostKeys::add);
 		} catch (IOException | GeneralSecurityException e) {
 			// Ignore.
 		}
-		server.setKeyPairProvider(() -> hostKeys);
+		server.setKeyPairProvider(session -> hostKeys);
 
 		configureAuthentication();
 
@@ -276,13 +278,15 @@ protected void configureShell() {
 	public void addHostKey(@NonNull Path key, boolean inFront)
 			throws IOException, GeneralSecurityException {
 		try (InputStream in = Files.newInputStream(key)) {
-			KeyPair pair = SecurityUtils.loadKeyPairIdentity(key.toString(), in,
-					null);
+			Iterable<KeyPair> pairs = SecurityUtils.loadKeyPairIdentities(null,
+					NamedResource.ofName(key.toString()), in, null);
+			for (KeyPair pair : pairs) {
 			if (inFront) {
 				hostKeys.add(0, pair);
 			} else {
 				hostKeys.add(pair);
 			}
+			}
 		}
 	}
 
@@ -335,14 +339,14 @@ public void stop() throws IOException {
 	public void setTestUserPublicKey(Path key)
 			throws IOException, GeneralSecurityException {
 		this.testKey = AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
-				.resolvePublicKey(PublicKeyEntryResolver.IGNORING);
+				.resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
 	}
 
 	private class GitUploadPackCommand extends AbstractCommandSupport {
 
 		protected GitUploadPackCommand(String command,
-				ExecutorService executorService) {
-			super(command, executorService, false);
+				CloseableExecutorService executorService) {
+			super(command, executorService);
 		}
 
 		@Override
@@ -370,8 +374,8 @@ public void run() {
 	private class GitReceivePackCommand extends AbstractCommandSupport {
 
 		protected GitReceivePackCommand(String command,
-				ExecutorService executorService) {
-			super(command, executorService, false);
+				CloseableExecutorService executorService) {
+			super(command, executorService);
 		}
 
 		@Override
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 25ebc48a3..40b0a273f 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -32,46 +32,46 @@ Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.3.0";x-inter
    org.apache.sshd.client.session,
    org.apache.sshd.client.keyverifier"
 Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
- 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.config.keys.loader;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.helpers;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.closeable;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.common.util.security;version="[2.0.0,2.1.0)",
- org.apache.sshd.server.auth;version="[2.0.0,2.1.0)",
+ org.apache.sshd.agent;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.auth;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.auth.password;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.channel;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.config.hosts;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.config.keys;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.future;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.keyverifier;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.session;version="[2.2.0,2.3.0)",
+ org.apache.sshd.client.subsystem.sftp;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.auth;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.channel;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.compression;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.config.keys;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.config.keys.loader;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.digest;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.forward;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.future;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.helpers;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.io;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.kex;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.keyprovider;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.mac;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.random;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.session;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.session.helpers;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.signature;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.subsystem.sftp;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.buffer;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.closeable;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.io;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.logging;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.net;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.security;version="[2.2.0,2.3.0)",
+ org.apache.sshd.server.auth;version="[2.2.0,2.3.0)",
  org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
  org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
  org.eclipse.jgit.fnmatch;version="[5.3.0,5.4.0)",
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index a00ce3141..120f63c63 100644
--- a/org.eclipse.jgit.ssh.apache/pom.xml
+++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -75,7 +75,7 @@
 
     <dependency>
       <groupId>org.apache.sshd</groupId>
-      <artifactId>sshd-core</artifactId>
+      <artifactId>sshd-osgi</artifactId>
       <version>${apache-sshd-version}</version>
     </dependency>
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
index 1072f3254..7efb7f1c5 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
@@ -54,9 +54,9 @@
 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.NamedResource;
+import org.apache.sshd.common.session.SessionContext;
 import org.eclipse.jgit.transport.sshd.KeyCache;
 
 /**
@@ -66,8 +66,6 @@
 public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider
 		implements Iterable<KeyPair> {
 
-	private final KeyCache cache;
-
 	/**
 	 * Creates a new {@link CachingKeyPairProvider} using the given
 	 * {@link KeyCache}. If the cache is {@code null}, this is a simple
@@ -80,7 +78,6 @@
 	 */
 	public CachingKeyPairProvider(List<Path> paths, KeyCache cache) {
 		super(paths);
-		this.cache = cache;
 	}
 
 	@Override
@@ -89,16 +86,29 @@ public CachingKeyPairProvider(List<Path> paths, KeyCache cache) {
 		if (resources.isEmpty()) {
 			return Collections.emptyListIterator();
 		}
-		return new CancellingKeyPairIterator(resources);
+		Collection<KeyPair> c = new ArrayList<>();
+		for (Path r : resources) {
+			try {
+				doLoadKeys(sessioncontext, r).forEach(c::add);
+			} catch (IOException | GeneralSecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		return c.iterator();
 	}
 
+	private SessionContext sessioncontext;
+
 	@Override
-	public Iterable<KeyPair> loadKeys() {
+	public Iterable<KeyPair> loadKeys(SessionContext session) {
+		this.sessioncontext = session;
 		return this;
 	}
 
 	@Override
-	protected KeyPair doLoadKey(Path resource)
+	protected Iterable<KeyPair> doLoadKeys(SessionContext session,
+			Path resource)
 			throws IOException, GeneralSecurityException {
 		if (!Files.exists(resource)) {
 			log.warn(format(SshdText.get().identityFileNotFound, resource));
@@ -107,74 +117,8 @@ protected KeyPair doLoadKey(Path resource)
 		// 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;
+		NamedResource resourceId = NamedResource.ofName(resource.toString());
+		return doLoadKeys(session, resourceId, resource, getPasswordFinder());
 	}
 
-	private class CancellingKeyPairIterator implements Iterator<KeyPair> {
-
-		private final Iterator<Path> paths;
-
-		private KeyPair nextItem;
-
-		private boolean nextSet;
-
-		public CancellingKeyPairIterator(Collection<? extends Path> resources) {
-			List<Path> copy = new ArrayList<>(resources.size());
-			copy.addAll(resources);
-			paths = copy.iterator();
-		}
-
-		@Override
-		public boolean hasNext() {
-			if (nextSet) {
-				return nextItem != null;
-			}
-			nextSet = true;
-			while (nextItem == null && paths.hasNext()) {
-				try {
-					nextItem = doLoadKey(paths.next());
-				} catch (CancellationException cancelled) {
-					throw cancelled;
-				} catch (Exception other) {
-					log.warn(other.toString());
-				}
-			}
-			return nextItem != null;
-		}
-
-		@Override
-		public KeyPair next() {
-			if (!nextSet && !hasNext()) {
-				throw new NoSuchElementException();
-			}
-			KeyPair result = nextItem;
-			nextItem = null;
-			nextSet = false;
-			if (result == null) {
-				throw new NoSuchElementException();
-			}
-			return result;
-		}
-
-	}
 }
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
index ef8e61181..431a5a032 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
@@ -51,24 +51,23 @@
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
 import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.security.auth.DestroyFailedException;
-
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.FilePasswordProvider.ResourceDecodeResult;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
 import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
-import org.eclipse.jgit.internal.transport.sshd.RepeatingFilePasswordProvider.ResourceDecodeResult;
 
 /**
  * A {@link FileKeyPairProvider} that asks repeatedly for a passphrase for an
  * encrypted private key if the {@link FilePasswordProvider} is a
- * {@link RepeatingFilePasswordProvider}.
+ * {@link PasswordProviderWrapper}.
  */
 public abstract class EncryptedFileKeyPairProvider extends FileKeyPairProvider {
 
@@ -88,11 +87,13 @@ public EncryptedFileKeyPairProvider(List<Path> paths) {
 	}
 
 	@Override
-	protected KeyPair doLoadKey(String resourceKey, InputStream inputStream,
+	protected Iterable<KeyPair> doLoadKeys(SessionContext session,
+			NamedResource resourceKey, InputStream inputStream,
 			FilePasswordProvider provider)
 			throws IOException, GeneralSecurityException {
-		if (!(provider instanceof RepeatingFilePasswordProvider)) {
-			return super.doLoadKey(resourceKey, inputStream, provider);
+		if (!(provider instanceof PasswordProviderWrapper)) {
+			return super.doLoadKeys(session, resourceKey, inputStream,
+					provider);
 		}
 		KeyPairResourceParser parser = SecurityUtils.getKeyPairResourceParser();
 		if (parser == null) {
@@ -100,22 +101,25 @@ protected KeyPair doLoadKey(String resourceKey, InputStream inputStream,
 			throw new NoSuchProviderException(
 					"No registered key-pair resource parser"); //$NON-NLS-1$
 		}
-		RepeatingFilePasswordProvider realProvider = (RepeatingFilePasswordProvider) provider;
+		PasswordProviderWrapper realProvider = (PasswordProviderWrapper) provider;
 		// Read the stream now so that we can process the content several
 		// times.
 		List<String> lines = IoUtils.readAllLines(inputStream);
 		Collection<KeyPair> ids = null;
 		while (ids == null) {
 			try {
-				ids = parser.loadKeyPairs(resourceKey, realProvider, lines);
-				realProvider.handleDecodeAttemptResult(resourceKey, "", null); //$NON-NLS-1$
+				ids = parser.loadKeyPairs(session, resourceKey, realProvider,
+						lines);
+				realProvider.handleDecodeAttemptResult(session, resourceKey, 0,
+						"", null); //$NON-NLS-1$
 				// No exception; success. Exit the loop even if ids is still
 				// null!
 				break;
 			} catch (IOException | GeneralSecurityException
 					| RuntimeException e) {
 				ResourceDecodeResult loadResult = realProvider
-						.handleDecodeAttemptResult(resourceKey, "", e); //$NON-NLS-1$
+						.handleDecodeAttemptResult(session, resourceKey, 0, "", //$NON-NLS-1$
+								e);
 				if (loadResult == null
 						|| loadResult == ResourceDecodeResult.TERMINATE) {
 					throw e;
@@ -138,21 +142,6 @@ protected KeyPair doLoadKey(String resourceKey, InputStream inputStream,
 			throw new InvalidKeyException(format(
 					SshdText.get().identityFileUnsupportedFormat, resourceKey));
 		}
-		KeyPair result = keys.next();
-		if (keys.hasNext()) {
-			log.warn(format(SshdText.get().identityFileMultipleKeys,
-					resourceKey));
-			keys.forEachRemaining(k -> {
-				PrivateKey pk = k.getPrivate();
-				if (pk != null) {
-					try {
-						pk.destroy();
-					} catch (DestroyFailedException e) {
-						// Ignore
-					}
-				}
-			});
-		}
-		return result;
+		return ids;
 	}
 }
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
index 9b4694c45..0a807b872 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -175,7 +175,13 @@ protected IoWriteFuture sendIdentification(String ident)
 				throw new IOException(other.getLocalizedMessage(), other);
 			}
 		} else {
-			return sendStartSsh();
+			try {
+				return sendStartSsh();
+			} catch (IOException e) {
+				throw e;
+			} catch (Exception other) {
+				throw new IOException(other.getLocalizedMessage(), other);
+			}
 		}
 	}
 
@@ -184,10 +190,10 @@ protected IoWriteFuture sendIdentification(String ident)
 	 * identification and the KEX init message.
 	 *
 	 * @return the client's KEX seed
-	 * @throws IOException
+	 * @throws Exception
 	 *             if something goes wrong
 	 */
-	private byte[] sendStartSsh() throws IOException {
+	private byte[] sendStartSsh() throws Exception {
 		super.sendIdentification(clientVersion);
 		return super.sendKexInit();
 	}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
index cda12623d..ee6e2bf58 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java
@@ -44,6 +44,7 @@
 
 import java.io.IOException;
 import java.nio.channels.Channel;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.PublicKey;
 import java.util.ArrayList;
@@ -140,7 +141,7 @@ public JGitPublicKeyIterator(ClientSession session,
 		keys.add(
 				new KeyPairIdentityIterator(session.getRegisteredIdentities(),
 						session, signatureFactories));
-		keys.add(new KeyPairIdentityIterator(session.getKeyPairProvider(),
+		keys.add(new KeyPairIdentityIterator(session.getKeyIdentityProvider(),
 				session, signatureFactories));
 		keyIter = keys.iterator();
 	}
@@ -255,7 +256,17 @@ public KeyPairIdentityIterator(KeyIdentityProvider provider,
 				SignatureFactoriesManager signatureFactories) {
 			this.session = session;
 			this.signatureFactories = signatureFactories;
-			keyPairs = provider == null ? null : provider.loadKeys().iterator();
+			Iterator<KeyPair> kps = null;
+			try {
+				if (provider != null) {
+					kps = provider.loadKeys(session).iterator();
+				}
+			} catch (IOException | GeneralSecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} finally {
+				keyPairs = kps;
+			}
 		}
 
 		@Override
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
index b9ff5e520..3e62ad63e 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
@@ -52,6 +52,7 @@
 import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.util.Arrays;
 import java.util.Iterator;
@@ -71,7 +72,8 @@
 import org.apache.sshd.common.io.IoConnectFuture;
 import org.apache.sshd.common.io.IoSession;
 import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.session.helpers.AbstractSession;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.eclipse.jgit.internal.transport.sshd.proxy.HttpClientConnector;
@@ -149,7 +151,7 @@ public ConnectFuture connect(HostConfigEntry hostConfig)
 			address = configureProxy(proxy, address);
 			proxy.clearPassword();
 		}
-		connector.connect(address).addListener(listener);
+		connector.connect(address, null, null).addListener(listener);
 		return connectFuture;
 	}
 
@@ -244,8 +246,8 @@ private JGitClientSession createSession(IoSession ioSession,
 		session.getProperties().put(PASSWORD_PROMPTS,
 				Integer.valueOf(numberOfPasswordPrompts));
 		FilePasswordProvider passwordProvider = getFilePasswordProvider();
-		if (passwordProvider instanceof RepeatingFilePasswordProvider) {
-			((RepeatingFilePasswordProvider) passwordProvider)
+		if (passwordProvider instanceof PasswordProviderWrapper) {
+			((PasswordProviderWrapper) passwordProvider)
 					.setAttempts(numberOfPasswordPrompts);
 		}
 		List<Path> identities = hostConfig.getIdentities().stream()
@@ -263,16 +265,16 @@ private JGitClientSession createSession(IoSession ioSession,
 				identities, keyCache);
 		ourConfiguredKeysProvider.setPasswordFinder(passwordProvider);
 		if (hostConfig.isIdentitiesOnly()) {
-			session.setKeyPairProvider(ourConfiguredKeysProvider);
+			session.setKeyIdentityProvider(ourConfiguredKeysProvider);
 		} else {
-			KeyPairProvider defaultKeysProvider = getKeyPairProvider();
+			KeyIdentityProvider defaultKeysProvider = getKeyIdentityProvider();
 			if (defaultKeysProvider instanceof AbstractResourceKeyPairProvider<?>) {
 				((AbstractResourceKeyPairProvider<?>) defaultKeysProvider)
 						.setPasswordFinder(passwordProvider);
 			}
-			KeyPairProvider combinedProvider = new CombinedKeyPairProvider(
+			KeyIdentityProvider combinedProvider = new CombinedKeyPairProvider(
 					ourConfiguredKeysProvider, defaultKeysProvider);
-			session.setKeyPairProvider(combinedProvider);
+			session.setKeyIdentityProvider(combinedProvider);
 		}
 		return session;
 	}
@@ -363,39 +365,29 @@ protected ClientSessionImpl doCreateSession(IoSession ioSession)
 	}
 
 	/**
-	 * A {@link KeyPairProvider} that iterates over the {@link Iterable}s
-	 * returned by other {@link KeyPairProvider}s.
+	 * A {@link KeyIdentityProvider} that iterates over the {@link Iterable}s
+	 * returned by other {@link KeyIdentityProvider}s.
 	 */
-	private static class CombinedKeyPairProvider implements KeyPairProvider {
+	private static class CombinedKeyPairProvider
+			implements KeyIdentityProvider {
 
-		private final List<KeyPairProvider> providers;
+		private final List<KeyIdentityProvider> providers;
 
-		public CombinedKeyPairProvider(KeyPairProvider... providers) {
+		public CombinedKeyPairProvider(KeyIdentityProvider... providers) {
 			this(Arrays.stream(providers).filter(Objects::nonNull)
 					.collect(Collectors.toList()));
 		}
 
-		public CombinedKeyPairProvider(List<KeyPairProvider> providers) {
+		public CombinedKeyPairProvider(List<KeyIdentityProvider> 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() {
+		public Iterable<KeyPair> loadKeys(SessionContext session) {
 			return () -> new Iterator<KeyPair>() {
 
-				private Iterator<KeyPairProvider> factories = providers.iterator();
+				private Iterator<KeyIdentityProvider> factories = providers
+						.iterator();
 				private Iterator<KeyPair> current;
 
 				private Boolean hasElement;
@@ -407,7 +399,13 @@ public boolean hasNext() {
 					}
 					while (current == null || !current.hasNext()) {
 						if (factories.hasNext()) {
-							current = factories.next().loadKeys().iterator();
+							try {
+								current = factories.next().loadKeys(session)
+										.iterator();
+							} catch (IOException | GeneralSecurityException e) {
+								// TODO Auto-generated catch block
+								e.printStackTrace();
+							}
 						} else {
 							current = null;
 							hasElement = Boolean.FALSE;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
index 984643961..a8407d5ad 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
@@ -47,11 +47,13 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.net.SocketAddress;
 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.AttributeRepository;
 import org.apache.sshd.common.util.net.SshdSocketAddress;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
@@ -101,7 +103,8 @@ public JGitSshConfig(@NonNull File home, @NonNull File config,
 
 	@Override
 	public HostConfigEntry resolveEffectiveHost(String host, int port,
-			String username) throws IOException {
+			SocketAddress localAddress, String username,
+			AttributeRepository context) throws IOException {
 		HostEntry entry = configFile.lookup(host, port, username);
 		JGitHostConfigEntry config = new JGitHostConfigEntry();
 		// Apache MINA conflates all keys, even multi-valued ones, in one map
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
index 7d8f3fd39..1da1c38d3 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
@@ -673,7 +673,7 @@ public HostKeyFile(Path path) {
 						continue;
 					}
 					try {
-						PublicKey serverKey = keyPart.resolvePublicKey(
+						PublicKey serverKey = keyPart.resolvePublicKey(null,
 								PublicKeyEntryResolver.IGNORING);
 						if (serverKey == null) {
 							LOG.warn(format(
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
index 93bd10285..b89732133 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
@@ -46,25 +46,23 @@
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.Arrays;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.sshd.KeyPasswordProvider;
 
 /**
- * A bridge from sshd's {@link RepeatingFilePasswordProvider} to our
+ * A bridge from sshd's {@link FilePasswordProvider} to our
  * {@link KeyPasswordProvider} API.
  */
-public class PasswordProviderWrapper implements RepeatingFilePasswordProvider {
+public class PasswordProviderWrapper implements FilePasswordProvider {
 
 	private final KeyPasswordProvider delegate;
 
-	private Map<String, AtomicInteger> counts = new ConcurrentHashMap<>();
-
 	/**
 	 * @param delegate
 	 */
@@ -72,21 +70,25 @@ public PasswordProviderWrapper(@NonNull KeyPasswordProvider delegate) {
 		this.delegate = delegate;
 	}
 
-	@Override
+	/**
+	 * @param numberOfPasswordPrompts
+	 */
 	public void setAttempts(int numberOfPasswordPrompts) {
 		delegate.setAttempts(numberOfPasswordPrompts);
 	}
 
-	@Override
+	/**
+	 * @return number of attempts
+	 */
 	public int getAttempts() {
 		return delegate.getAttempts();
 	}
 
 	@Override
-	public String getPassword(String resourceKey) throws IOException {
-		int attempt = counts
-				.computeIfAbsent(resourceKey, k -> new AtomicInteger()).get();
-		char[] passphrase = delegate.getPassphrase(toUri(resourceKey), attempt);
+	public String getPassword(SessionContext session, NamedResource resourceKey,
+			int retryIndex) throws IOException {
+		char[] passphrase = delegate.getPassphrase(toUri(resourceKey.getName()),
+				retryIndex);
 		if (passphrase == null) {
 			return null;
 		}
@@ -98,23 +100,17 @@ public String getPassword(String resourceKey) throws IOException {
 	}
 
 	@Override
-	public ResourceDecodeResult handleDecodeAttemptResult(String resourceKey,
+	public ResourceDecodeResult handleDecodeAttemptResult(
+			SessionContext session, NamedResource resourceKey, int retryIndex,
 			String password, Exception err)
 			throws IOException, GeneralSecurityException {
-		AtomicInteger count = counts.get(resourceKey);
-		int numberOfAttempts = count == null ? 0 : count.incrementAndGet();
 		ResourceDecodeResult result = null;
-		try {
-			if (delegate.keyLoaded(toUri(resourceKey), numberOfAttempts, err)) {
+			if (delegate.keyLoaded(toUri(resourceKey.getName()), retryIndex,
+					err)) {
 				result = ResourceDecodeResult.RETRY;
 			} else {
 				result = ResourceDecodeResult.TERMINATE;
 			}
-		} finally {
-			if (result != ResourceDecodeResult.RETRY) {
-				counts.remove(resourceKey);
-			}
-		}
 		return result;
 	}
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
deleted file mode 100644
index e491cae13..000000000
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.security.GeneralSecurityException;
-
-import org.apache.sshd.common.config.keys.FilePasswordProvider;
-
-/**
- * A {@link FilePasswordProvider} augmented to support repeatedly asking for
- * passwords.
- *
- */
-public interface RepeatingFilePasswordProvider extends FilePasswordProvider {
-
-	/**
-	 * Define the maximum number of attempts to get a password that should be
-	 * attempted for one identity resource through this provider.
-	 *
-	 * @param numberOfPasswordPrompts
-	 *            number of times to ask for a password;
-	 *            {@link IllegalArgumentException} may be thrown if <= 0
-	 */
-	void setAttempts(int numberOfPasswordPrompts);
-
-	/**
-	 * Gets the maximum number of attempts to get a password that should be
-	 * attempted for one identity resource through this provider.
-	 *
-	 * @return the maximum number of attempts to try, always >= 1.
-	 */
-	default int getAttempts() {
-		return 1;
-	}
-
-	// The following part of this interface is from the upstream resolution of
-	// SSHD-850. See https://github.com/apache/mina-sshd/commit/f19bd2e34 .
-	// TODO: remove this once we move to sshd > 2.1.0
-
-	/**
-	 * Result value of
-	 * {@link RepeatingFilePasswordProvider#handleDecodeAttemptResult(String, String, Exception)}.
-	 */
-	public enum ResourceDecodeResult {
-		/** Re-throw the decoding exception. */
-		TERMINATE,
-		/** Retry the decoding process - including password prompt. */
-		RETRY,
-		/** Skip attempt and see if we can proceed without the key. */
-		IGNORE;
-	}
-
-	/**
-	 * Invoked to inform the password provider about the decoding result.
-	 * <b>Note:</b> any exception thrown from this method (including if called
-	 * to inform about success) will be propagated instead of the original (if
-	 * any was reported)
-	 *
-	 * @param resourceKey
-	 *            The resource key representing the <U>private</U> file
-	 * @param password
-	 *            The password that was attempted
-	 * @param err
-	 *            The attempt result - {@code null} for success
-	 * @return How to proceed in case of error - <u>ignored</u> if invoked in
-	 *         order to report success. <b>Note:</b> {@code null} is same as
-	 *         {@link ResourceDecodeResult#TERMINATE}.
-	 * @throws IOException
-	 * @throws GeneralSecurityException
-	 */
-	ResourceDecodeResult handleDecodeAttemptResult(String resourceKey,
-			String password, Exception err)
-			throws IOException, GeneralSecurityException;
-}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
index cdd47bf32..1968e795c 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
@@ -69,7 +69,7 @@
 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.KeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
@@ -211,7 +211,7 @@ public SshdSession getSession(URIish uri,
 				}
 				HostConfigEntryResolver configFile = getHostConfigEntryResolver(
 						home, sshDir);
-				KeyPairProvider defaultKeysProvider = toKeyPairProvider(
+				KeyIdentityProvider defaultKeysProvider = toKeyIdentityProvider(
 						getDefaultKeys(sshDir));
 				KeyPasswordProvider passphrases = createKeyPasswordProvider(
 						credentialsProvider);
@@ -227,7 +227,7 @@ public SshdSession getSession(URIish uri,
 				client.setUserInteraction(
 						new JGitUserInteraction(credentialsProvider));
 				client.setUserAuthFactories(getUserAuthFactories());
-				client.setKeyPairProvider(defaultKeysProvider);
+				client.setKeyIdentityProvider(defaultKeysProvider);
 				// JGit-specific things:
 				JGitSshClient jgitClient = (JGitSshClient) client;
 				jgitClient.setKeyCache(getKeyCache());
@@ -438,17 +438,18 @@ private ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir,
 
 	/**
 	 * Converts an {@link Iterable} of {link KeyPair}s into a
-	 * {@link KeyPairProvider}.
+	 * {@link KeyIdentityProvider}.
 	 *
 	 * @param keys
-	 *            to provide via the returned {@link KeyPairProvider}
-	 * @return a {@link KeyPairProvider} that provides the given {@code keys}
+	 *            to provide via the returned {@link KeyIdentityProvider}
+	 * @return a {@link KeyIdentityProvider} that provides the given
+	 *         {@code keys}
 	 */
-	private KeyPairProvider toKeyPairProvider(Iterable<KeyPair> keys) {
-		if (keys instanceof KeyPairProvider) {
-			return (KeyPairProvider) keys;
+	private KeyIdentityProvider toKeyIdentityProvider(Iterable<KeyPair> keys) {
+		if (keys instanceof KeyIdentityProvider) {
+			return (KeyIdentityProvider) keys;
 		}
-		return () -> keys;
+		return (session) -> keys;
 	}
 
 	/**
diff --git a/pom.xml b/pom.xml
index cc90a7e2e..f2bf35dc7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -183,7 +183,7 @@
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
     <jgit-last-release-version>5.2.0.201812061821-r</jgit-last-release-version>
-    <apache-sshd-version>2.0.0</apache-sshd-version>
+    <apache-sshd-version>2.2.0</apache-sshd-version>
     <jsch-version>0.1.54</jsch-version>
     <jzlib-version>1.1.1</jzlib-version>
     <javaewah-version>1.1.6</javaewah-version>
-- 
2.20.1