Browse Source
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>stable-5.4
Thomas Wolf
6 years ago
committed by
Matthias Sohn
36 changed files with 271 additions and 885 deletions
@ -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; |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue