diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2019-01-14 17:30:03 +0100 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2019-05-06 15:22:05 +0200 |
commit | 86cee68e0d9282ecc6a49792693309e8d5d9d984 (patch) | |
tree | 7a4745417f0bcbd9f5e998f21f4703db38ee19c2 /org.eclipse.jgit.ssh.apache | |
parent | 756c2c2b3c9be5f9c487c08de868acaeb43348d9 (diff) | |
download | jgit-86cee68e0d9282ecc6a49792693309e8d5d9d984.tar.gz jgit-86cee68e0d9282ecc6a49792693309e8d5d9d984.zip |
Apache MINA sshd client: adapt to sshd 2.2.0
Update target platforms, maven and bazel builds to use sshd 2.2.0.
Adapt internal classes to changed sshd interfaces and remove previous
work-arounds for asking repeatedly for key passwords and for loading
keys lazily; both are now done by sshd.
CQ: 19034
CQ: 19035
Bug: 541425
Change-Id: I85e1df6ebb8a94953a912d9b2b8a7b5bdfbd608a
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.ssh.apache')
16 files changed, 174 insertions, 790 deletions
diff --git a/org.eclipse.jgit.ssh.apache/BUILD b/org.eclipse.jgit.ssh.apache/BUILD index a1a6c8e24c..372cfc228f 100644 --- a/org.eclipse.jgit.ssh.apache/BUILD +++ b/org.eclipse.jgit.ssh.apache/BUILD @@ -12,7 +12,7 @@ java_library( deps = [ "//lib:eddsa", "//lib:slf4j-api", - "//lib:sshd-core", + "//lib:sshd-osgi", "//lib:sshd-sftp", "//org.eclipse.jgit:jgit", ], diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF index 96dbd8a4ad..d1f7d49826 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF @@ -32,46 +32,47 @@ Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.4.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.io.resource;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.4.0,5.5.0)", org.eclipse.jgit.errors;version="[5.4.0,5.5.0)", org.eclipse.jgit.fnmatch;version="[5.4.0,5.5.0)", diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml index 242957a062..31bf6d7d77 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 1072f32548..a1ec31883d 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 @@ -45,10 +45,13 @@ package org.eclipse.jgit.internal.transport.sshd; import static java.text.MessageFormat.format; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; import java.security.KeyPair; +import java.security.PrivateKey; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -57,13 +60,20 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.CancellationException; +import javax.security.auth.DestroyFailedException; + +import org.apache.sshd.common.NamedResource; +import org.apache.sshd.common.config.keys.FilePasswordProvider; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; +import org.apache.sshd.common.session.SessionContext; +import org.apache.sshd.common.util.io.resource.IoResource; +import org.apache.sshd.common.util.security.SecurityUtils; import org.eclipse.jgit.transport.sshd.KeyCache; /** - * A {@link EncryptedFileKeyPairProvider} that uses an external - * {@link KeyCache}. + * A {@link FileKeyPairProvider} that uses an external {@link KeyCache}. */ -public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider +public class CachingKeyPairProvider extends FileKeyPairProvider implements Iterable<KeyPair> { private final KeyCache cache; @@ -71,7 +81,7 @@ public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider /** * Creates a new {@link CachingKeyPairProvider} using the given * {@link KeyCache}. If the cache is {@code null}, this is a simple - * {@link EncryptedFileKeyPairProvider}. + * {@link FileKeyPairProvider}. * * @param paths * to load keys from @@ -85,36 +95,36 @@ public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider @Override public Iterator<KeyPair> iterator() { + return iterator(null); + } + + private Iterator<KeyPair> iterator(SessionContext session) { Collection<? extends Path> resources = getPaths(); if (resources.isEmpty()) { return Collections.emptyListIterator(); } - return new CancellingKeyPairIterator(resources); + return new CancellingKeyPairIterator(session, resources); } @Override - public Iterable<KeyPair> loadKeys() { - return this; + public Iterable<KeyPair> loadKeys(SessionContext session) { + return () -> iterator(session); } - @Override - protected KeyPair doLoadKey(Path resource) + private KeyPair loadKey(SessionContext session, Path path) throws IOException, GeneralSecurityException { - if (!Files.exists(resource)) { - log.warn(format(SshdText.get().identityFileNotFound, resource)); + if (!Files.exists(path)) { + log.warn(format(SshdText.get().identityFileNotFound, path)); return null; } - // 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(); + IoResource<Path> resource = getIoResource(session, path); if (cache == null) { - return doLoadKey(resourceId, resource, getPasswordFinder()); + return loadKey(session, resource, path, getPasswordFinder()); } Throwable t[] = { null }; - KeyPair key = cache.get(resource, p -> { + KeyPair key = cache.get(path, p -> { try { - return doLoadKey(resourceId, p, getPasswordFinder()); + return loadKey(session, resource, p, getPasswordFinder()); } catch (IOException | GeneralSecurityException e) { t[0] = e; return null; @@ -130,18 +140,55 @@ public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider return key; } + private KeyPair loadKey(SessionContext session, NamedResource resource, + Path path, FilePasswordProvider passwordProvider) + throws IOException, GeneralSecurityException { + try (InputStream stream = Files.newInputStream(path)) { + Iterable<KeyPair> ids = SecurityUtils.loadKeyPairIdentities(session, + resource, stream, passwordProvider); + if (ids == null) { + throw new InvalidKeyException( + format(SshdText.get().identityFileNoKey, path)); + } + Iterator<KeyPair> keys = ids.iterator(); + if (!keys.hasNext()) { + throw new InvalidKeyException(format( + SshdText.get().identityFileUnsupportedFormat, path)); + } + KeyPair result = keys.next(); + if (keys.hasNext()) { + log.warn(format(SshdText.get().identityFileMultipleKeys, path)); + keys.forEachRemaining(k -> { + PrivateKey pk = k.getPrivate(); + if (pk != null) { + try { + pk.destroy(); + } catch (DestroyFailedException e) { + // Ignore + } + } + }); + } + return result; + } + } + private class CancellingKeyPairIterator implements Iterator<KeyPair> { + private final SessionContext context; + private final Iterator<Path> paths; private KeyPair nextItem; private boolean nextSet; - public CancellingKeyPairIterator(Collection<? extends Path> resources) { + public CancellingKeyPairIterator(SessionContext session, + Collection<? extends Path> resources) { List<Path> copy = new ArrayList<>(resources.size()); copy.addAll(resources); paths = copy.iterator(); + context = session; } @Override @@ -152,7 +199,7 @@ public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider nextSet = true; while (nextItem == null && paths.hasNext()) { try { - nextItem = doLoadKey(paths.next()); + nextItem = loadKey(context, paths.next()); } catch (CancellationException cancelled) { throw cancelled; } catch (Exception other) { 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 deleted file mode 100644 index ef8e611811..0000000000 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java +++ /dev/null @@ -1,158 +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 static java.text.MessageFormat.format; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.security.GeneralSecurityException; -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.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; -import org.apache.sshd.common.keyprovider.FileKeyPairProvider; -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}. - */ -public abstract class EncryptedFileKeyPairProvider extends FileKeyPairProvider { - - // TODO: remove this class once we're based on sshd > 2.1.0. See upstream - // issue SSHD-850 https://issues.apache.org/jira/browse/SSHD-850 and commit - // https://github.com/apache/mina-sshd/commit/f19bd2e34 - - /** - * Creates a new {@link EncryptedFileKeyPairProvider} for the given - * {@link Path}s. - * - * @param paths - * to read keys from - */ - public EncryptedFileKeyPairProvider(List<Path> paths) { - super(paths); - } - - @Override - protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, - FilePasswordProvider provider) - throws IOException, GeneralSecurityException { - if (!(provider instanceof RepeatingFilePasswordProvider)) { - return super.doLoadKey(resourceKey, inputStream, provider); - } - KeyPairResourceParser parser = SecurityUtils.getKeyPairResourceParser(); - if (parser == null) { - // This is an internal configuration error, thus no translation. - throw new NoSuchProviderException( - "No registered key-pair resource parser"); //$NON-NLS-1$ - } - RepeatingFilePasswordProvider realProvider = (RepeatingFilePasswordProvider) 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$ - // 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$ - if (loadResult == null - || loadResult == ResourceDecodeResult.TERMINATE) { - throw e; - } else if (loadResult == ResourceDecodeResult.RETRY) { - continue; - } - // IGNORE doesn't make any sense here, but OK, let's ignore it. - // ids == null, so we'll throw an exception below. - break; - } - } - if (ids == null) { - // The javadoc on loadKeyPairs says it might return null if no - // key pair found. Bad API. - throw new InvalidKeyException( - format(SshdText.get().identityFileNoKey, resourceKey)); - } - Iterator<KeyPair> keys = ids.iterator(); - if (!keys.hasNext()) { - 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; - } -} 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 dcf330a2a4..56f8ade667 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 @@ -46,6 +46,7 @@ import static java.text.MessageFormat.format; import java.io.IOException; import java.net.SocketAddress; +import java.security.GeneralSecurityException; import java.security.PublicKey; import java.util.ArrayList; import java.util.Iterator; @@ -173,7 +174,8 @@ public class JGitClientSession extends ClientSessionImpl { } @Override - protected byte[] sendKexInit() throws IOException { + protected byte[] sendKexInit() + throws IOException, GeneralSecurityException { StatefulProxyConnector proxy = proxyHandler; if (proxy != null) { try { @@ -187,7 +189,7 @@ public class JGitClientSession extends ClientSessionImpl { // This is called only from the ClientSessionImpl // constructor, where the return value is ignored. return null; - } catch (IOException e) { + } catch (IOException | GeneralSecurityException e) { throw e; } catch (Exception other) { throw new IOException(other.getLocalizedMessage(), other); diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java index 7b22b88ab7..21e8beaeb4 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java @@ -53,28 +53,11 @@ 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. - * */ public class JGitHostConfigEntry extends HostConfigEntry { private Map<String, List<String>> multiValuedOptions; - @Override - public String getProperty(String name, String defaultValue) { - // Upstream bug fix (SSHD-867): if there are _no_ properties at all, the - // super implementation returns always null even if a default value is - // given. - // - // See https://issues.apache.org/jira/projects/SSHD/issues/SSHD-867 - // - // TODO: remove this override once we're based on sshd > 2.1.0 - Map<String, String> properties = getProperties(); - if (properties == null || properties.isEmpty()) { - return defaultValue; - } - return super.getProperty(name, defaultValue); - } - /** * Sets the multi-valued options. * diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java deleted file mode 100644 index 0b3de4ace3..0000000000 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java +++ /dev/null @@ -1,83 +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.util.List; - -import org.apache.sshd.client.auth.AbstractUserAuthFactory; -import org.apache.sshd.client.auth.UserAuth; -import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory; -import org.apache.sshd.common.NamedFactory; -import org.apache.sshd.common.signature.Signature; -import org.apache.sshd.common.signature.SignatureFactoriesManager; - -/** - * A customized authentication factory for public key user authentication. The - * default implementation {@link UserAuthPublicKeyFactory} ends up doing some - * crazy stream "magic" that loads too many keys too early. - */ -public class JGitPublicKeyAuthFactory extends AbstractUserAuthFactory - implements SignatureFactoriesManager { - - /** The singleton {@link JGitPublicKeyAuthFactory}. */ - public static final JGitPublicKeyAuthFactory INSTANCE = new JGitPublicKeyAuthFactory(); - - private JGitPublicKeyAuthFactory() { - super(UserAuthPublicKeyFactory.NAME); - } - - @Override - public UserAuth create() { - return new JGitPublicKeyAuthentication(getSignatureFactories()); - } - - @Override - public List<NamedFactory<Signature>> getSignatureFactories() { - return null; - } - - @Override - public void setSignatureFactories(List<NamedFactory<Signature>> factories) { - throw new UnsupportedOperationException(); - } -} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java deleted file mode 100644 index 63b3990b13..0000000000 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java +++ /dev/null @@ -1,103 +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.util.List; - -import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.common.NamedFactory; -import org.apache.sshd.common.signature.Signature; - -/** - * A specialized public key authentication handler that uses our own - * {@link JGitPublicKeyIterator}. The super class creates in - * {@link #init(ClientSession, String)} a - * {@link org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator}, which - * in its constructor does some strange {@link java.util.stream.Stream} "magic" - * that ends up loading keys prematurely. - */ -public class JGitPublicKeyAuthentication extends UserAuthPublicKey { - - private ClientSession clientSession; - - private String serviceName; - - /** - * Creates a new {@link JGitPublicKeyAuthentication}. - * - * @param factories - * signature factories to use - */ - public JGitPublicKeyAuthentication( - List<NamedFactory<Signature>> factories) { - super(factories); - } - - @Override - public void init(ClientSession session, String service) throws Exception { - // Do *not* call super.init(); it'll create a UserAuthPublicKeyIterator - // and that's where things then go wrong. Instead, do the whole - // initialization directly here. - clientSession = session; - serviceName = service; - releaseKeys(); - // Use our own iterator! - keys = new JGitPublicKeyIterator(session, this); - } - - @Override - public ClientSession getClientSession() { - return clientSession; - } - - @Override - public ClientSession getSession() { - return clientSession; - } - - @Override - public String getService() { - return serviceName; - } -} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java deleted file mode 100644 index cda12623d8..0000000000 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyIterator.java +++ /dev/null @@ -1,275 +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.nio.channels.Channel; -import java.security.KeyPair; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.sshd.agent.SshAgent; -import org.apache.sshd.agent.SshAgentFactory; -import org.apache.sshd.client.auth.pubkey.AbstractKeyPairIterator; -import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity; -import org.apache.sshd.client.auth.pubkey.KeyPairIdentity; -import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity; -import org.apache.sshd.client.config.hosts.HostConfigEntry; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.common.FactoryManager; -import org.apache.sshd.common.keyprovider.KeyIdentityProvider; -import org.apache.sshd.common.signature.SignatureFactoriesManager; - -/** - * A new iterator over key pairs that we use instead of the default - * {@link org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator}, which - * in its constructor does some strange {@link java.util.stream.Stream} "magic" - * that ends up loading keys prematurely. This class uses plain - * {@link Iterator}s instead to avoid that problem. Used in - * {@link JGitPublicKeyAuthentication}. - * - * @see <a href= - * "https://issues.apache.org/jira/projects/SSHD/issues/SSHD-860">Upstream - * issue SSHD-860</a> - */ -public class JGitPublicKeyIterator - extends AbstractKeyPairIterator<PublicKeyIdentity> implements Channel { - - // Re: the cause for the problem mentioned above has not been determined. - // It looks as if either the Apache code inadvertently calls - // GenericUtils.isEmpty() on all streams (which would load the first key - // of each stream), or the Java stream implementation does some prefetching. - // It's not entirely clear. Using Iterators we have more control over - // what happens when. - - private final AtomicBoolean open = new AtomicBoolean(true); - - private SshAgent agent; - - private final List<Iterator<PublicKeyIdentity>> keys = new ArrayList<>(3); - - private final Iterator<Iterator<PublicKeyIdentity>> keyIter; - - private Iterator<PublicKeyIdentity> current; - - private Boolean hasElement; - - /** - * Creates a new {@link JGitPublicKeyIterator}. - * - * @param session - * we're trying to authenticate - * @param signatureFactories - * to use - * @throws Exception - * if an {@link SshAgentFactory} is configured and getting - * identities from the agent fails - */ - public JGitPublicKeyIterator(ClientSession session, - SignatureFactoriesManager signatureFactories) throws Exception { - super(session); - boolean useAgent = true; - if (session instanceof JGitClientSession) { - HostConfigEntry config = ((JGitClientSession) session) - .getHostConfigEntry(); - useAgent = !config.isIdentitiesOnly(); - } - if (useAgent) { - FactoryManager manager = session.getFactoryManager(); - SshAgentFactory factory = manager == null ? null - : manager.getAgentFactory(); - if (factory != null) { - try { - agent = factory.createClient(manager); - keys.add(new AgentIdentityIterator(agent)); - } catch (IOException e) { - try { - closeAgent(); - } catch (IOException err) { - e.addSuppressed(err); - } - throw e; - } - } - } - keys.add( - new KeyPairIdentityIterator(session.getRegisteredIdentities(), - session, signatureFactories)); - keys.add(new KeyPairIdentityIterator(session.getKeyPairProvider(), - session, signatureFactories)); - keyIter = keys.iterator(); - } - - @Override - public boolean isOpen() { - return open.get(); - } - - @Override - public void close() throws IOException { - if (open.getAndSet(false)) { - closeAgent(); - } - } - - @Override - public boolean hasNext() { - if (!isOpen()) { - return false; - } - if (hasElement != null) { - return hasElement.booleanValue(); - } - while (current == null || !current.hasNext()) { - if (keyIter.hasNext()) { - current = keyIter.next(); - } else { - current = null; - hasElement = Boolean.FALSE; - return false; - } - } - hasElement = Boolean.TRUE; - return true; - } - - @Override - public PublicKeyIdentity next() { - if (!isOpen() || hasElement == null && !hasNext() - || !hasElement.booleanValue()) { - throw new NoSuchElementException(); - } - hasElement = null; - PublicKeyIdentity result; - try { - result = current.next(); - } catch (NoSuchElementException e) { - result = null; - } - return result; - } - - private void closeAgent() throws IOException { - if (agent == null) { - return; - } - try { - agent.close(); - } finally { - agent = null; - } - } - - /** - * An {@link Iterator} that maps the data obtained from an agent to - * {@link PublicKeyIdentity}. - */ - private static class AgentIdentityIterator - implements Iterator<PublicKeyIdentity> { - - private final SshAgent agent; - - private final Iterator<? extends Map.Entry<PublicKey, String>> iter; - - public AgentIdentityIterator(SshAgent agent) throws IOException { - this.agent = agent; - iter = agent == null ? null : agent.getIdentities().iterator(); - } - - @Override - public boolean hasNext() { - return iter != null && iter.hasNext(); - } - - @Override - public PublicKeyIdentity next() { - if (iter == null) { - throw new NoSuchElementException(); - } - Map.Entry<PublicKey, String> entry = iter.next(); - return new KeyAgentIdentity(agent, entry.getKey(), - entry.getValue()); - } - } - - /** - * An {@link Iterator} that maps {@link KeyPair} to - * {@link PublicKeyIdentity}. - */ - private static class KeyPairIdentityIterator - implements Iterator<PublicKeyIdentity> { - - private final Iterator<KeyPair> keyPairs; - - private final ClientSession session; - - private final SignatureFactoriesManager signatureFactories; - - public KeyPairIdentityIterator(KeyIdentityProvider provider, - ClientSession session, - SignatureFactoriesManager signatureFactories) { - this.session = session; - this.signatureFactories = signatureFactories; - keyPairs = provider == null ? null : provider.loadKeys().iterator(); - } - - @Override - public boolean hasNext() { - return keyPairs != null && keyPairs.hasNext(); - } - - @Override - public PublicKeyIdentity next() { - if (keyPairs == null) { - throw new NoSuchElementException(); - } - KeyPair key = keyPairs.next(); - return new KeyPairIdentity(signatureFactories, session, key); - } - } -} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java index b9ff5e5208..98e71dfe4b 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 @@ -48,10 +48,12 @@ import static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.positive import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; +import java.net.SocketAddress; 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.KeyPair; import java.util.Arrays; import java.util.Iterator; @@ -66,12 +68,14 @@ 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.AttributeRepository; import org.apache.sshd.common.config.keys.FilePasswordProvider; 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.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; @@ -117,7 +121,8 @@ public class JGitSshClient extends SshClient { } @Override - public ConnectFuture connect(HostConfigEntry hostConfig) + public ConnectFuture connect(HostConfigEntry hostConfig, + AttributeRepository context, SocketAddress localAddress) throws IOException { if (connector == null) { throw new IllegalStateException("SshClient not started."); //$NON-NLS-1$ @@ -149,7 +154,7 @@ public class JGitSshClient extends SshClient { address = configureProxy(proxy, address); proxy.clearPassword(); } - connector.connect(address).addListener(listener); + connector.connect(address, this, localAddress).addListener(listener); return connectFuture; } @@ -263,16 +268,16 @@ public class JGitSshClient extends SshClient { 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 CombinedKeyIdentityProvider( ourConfiguredKeysProvider, defaultKeysProvider); - session.setKeyPairProvider(combinedProvider); + session.setKeyIdentityProvider(combinedProvider); } return session; } @@ -363,39 +368,30 @@ public class JGitSshClient extends SshClient { } /** - * 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 CombinedKeyIdentityProvider + implements KeyIdentityProvider { - private final List<KeyPairProvider> providers; + private final List<KeyIdentityProvider> providers; - public CombinedKeyPairProvider(KeyPairProvider... providers) { + public CombinedKeyIdentityProvider(KeyIdentityProvider... providers) { this(Arrays.stream(providers).filter(Objects::nonNull) .collect(Collectors.toList())); } - public CombinedKeyPairProvider(List<KeyPairProvider> providers) { + public CombinedKeyIdentityProvider( + 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 context) { 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 +403,12 @@ public class JGitSshClient extends SshClient { } while (current == null || !current.hasNext()) { if (factories.hasNext()) { - current = factories.next().loadKeys().iterator(); + try { + current = factories.next().loadKeys(context) + .iterator(); + } catch (IOException | GeneralSecurityException e) { + throw new RuntimeException(e); + } } 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 984643961f..6468b3e276 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 static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.positive 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 class JGitSshConfig implements HostConfigEntryResolver { @Override public HostConfigEntry resolveEffectiveHost(String host, int port, - String username) throws IOException { + SocketAddress localAddress, String username, + AttributeRepository attributes) 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 4246fbe3bc..381f7cfc22 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 @@ -672,7 +672,7 @@ public class OpenSshServerKeyVerifier 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 93bd10285a..bec65f1d3a 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 @@ -50,6 +50,8 @@ 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.session.SessionContext; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.URIish; @@ -83,10 +85,12 @@ public class PasswordProviderWrapper implements RepeatingFilePasswordProvider { } @Override - public String getPassword(String resourceKey) throws IOException { + public String getPassword(SessionContext session, NamedResource resource, + int attemptIndex) throws IOException { + String key = resource.getName(); int attempt = counts - .computeIfAbsent(resourceKey, k -> new AtomicInteger()).get(); - char[] passphrase = delegate.getPassphrase(toUri(resourceKey), attempt); + .computeIfAbsent(key, k -> new AtomicInteger()).get(); + char[] passphrase = delegate.getPassphrase(toUri(key), attempt); if (passphrase == null) { return null; } @@ -98,21 +102,23 @@ public class PasswordProviderWrapper implements RepeatingFilePasswordProvider { } @Override - public ResourceDecodeResult handleDecodeAttemptResult(String resourceKey, + public ResourceDecodeResult handleDecodeAttemptResult( + SessionContext session, NamedResource resource, int retryIndex, String password, Exception err) throws IOException, GeneralSecurityException { - AtomicInteger count = counts.get(resourceKey); + String key = resource.getName(); + AtomicInteger count = counts.get(key); int numberOfAttempts = count == null ? 0 : count.incrementAndGet(); ResourceDecodeResult result = null; try { - if (delegate.keyLoaded(toUri(resourceKey), numberOfAttempts, err)) { + if (delegate.keyLoaded(toUri(key), numberOfAttempts, err)) { result = ResourceDecodeResult.RETRY; } else { result = ResourceDecodeResult.TERMINATE; } } finally { if (result != ResourceDecodeResult.RETRY) { - counts.remove(resourceKey); + counts.remove(key); } } 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 index e491cae130..977f1a22fe 100644 --- 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 @@ -42,9 +42,6 @@ */ package org.eclipse.jgit.internal.transport.sshd; -import java.io.IOException; -import java.security.GeneralSecurityException; - import org.apache.sshd.common.config.keys.FilePasswordProvider; /** @@ -74,42 +71,4 @@ public interface RepeatingFilePasswordProvider extends FilePasswordProvider { 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 cdd47bf323..2f9691ed63 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 @@ -64,18 +64,18 @@ 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.pubkey.UserAuthPublicKeyFactory; 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.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; import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory; import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory; -import org.eclipse.jgit.internal.transport.sshd.JGitPublicKeyAuthFactory; import org.eclipse.jgit.internal.transport.sshd.JGitSshClient; import org.eclipse.jgit.internal.transport.sshd.JGitSshConfig; import org.eclipse.jgit.internal.transport.sshd.JGitUserInteraction; @@ -211,7 +211,7 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { } HostConfigEntryResolver configFile = getHostConfigEntryResolver( home, sshDir); - KeyPairProvider defaultKeysProvider = toKeyPairProvider( + KeyIdentityProvider defaultKeysProvider = toKeyIdentityProvider( getDefaultKeys(sshDir)); KeyPasswordProvider passphrases = createKeyPasswordProvider( credentialsProvider); @@ -227,7 +227,7 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { 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 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { /** * 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; } /** @@ -522,7 +523,7 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { // Password auth doesn't have this problem. return Collections.unmodifiableList( Arrays.asList(GssApiWithMicAuthFactory.INSTANCE, - JGitPublicKeyAuthFactory.INSTANCE, + UserAuthPublicKeyFactory.INSTANCE, JGitPasswordAuthFactory.INSTANCE, UserAuthKeyboardInteractiveFactory.INSTANCE)); } |